Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f72aa2ca5c | ||
|
|
e8ec6dbb31 | ||
|
|
d0be9ff067 | ||
|
|
3d7adff923 | ||
|
|
9c02100d23 | ||
|
|
08656b18bf | ||
|
|
497c1ad8b3 | ||
|
|
427078461a | ||
|
|
e7deea7039 |
@@ -0,0 +1,785 @@
|
||||
//! Experimental observer of Command::Layout; no quality thresholds or candidate algorithm.
|
||||
use oa_core::{
|
||||
projection::{self, ProjectedView},
|
||||
routing, *,
|
||||
};
|
||||
use serde_json::{Value, json};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
#[path = "auto_layout_probe/layered.rs"]
|
||||
mod layered;
|
||||
|
||||
type P = (f64, f64);
|
||||
type Rect = (f64, f64, f64, f64);
|
||||
const EPS: f64 = 0.0001;
|
||||
fn p(v: Position) -> P {
|
||||
(v.x as f64, v.y as f64)
|
||||
}
|
||||
fn sub(a: P, b: P) -> P {
|
||||
(a.0 - b.0, a.1 - b.1)
|
||||
}
|
||||
fn dot(a: P, b: P) -> f64 {
|
||||
a.0 * b.0 + a.1 * b.1
|
||||
}
|
||||
fn cross(a: P, b: P) -> f64 {
|
||||
a.0 * b.1 - a.1 * b.0
|
||||
}
|
||||
fn length(a: P) -> f64 {
|
||||
a.0.hypot(a.1)
|
||||
}
|
||||
fn rect(at: Position, size: Size) -> Rect {
|
||||
(
|
||||
at.x as f64,
|
||||
at.y as f64,
|
||||
(at.x + size.width) as f64,
|
||||
(at.y + size.height) as f64,
|
||||
)
|
||||
}
|
||||
fn overlap(a: Rect, b: Rect) -> f64 {
|
||||
let w = a.2.min(b.2) - a.0.max(b.0);
|
||||
let h = a.3.min(b.3) - a.1.max(b.1);
|
||||
if w > EPS && h > EPS { w * h } else { 0. }
|
||||
}
|
||||
fn contains(a: Rect, b: Rect) -> bool {
|
||||
a.0 <= b.0 + EPS && a.1 <= b.1 + EPS && a.2 + EPS >= b.2 && a.3 + EPS >= b.3
|
||||
}
|
||||
fn proper_cross(a: P, b: P, c: P, d: P) -> Option<P> {
|
||||
let u = sub(b, a);
|
||||
let v = sub(d, c);
|
||||
let denominator = cross(u, v);
|
||||
if denominator.abs() < 1e-9 {
|
||||
return None;
|
||||
}
|
||||
let t = cross(sub(c, a), v) / denominator;
|
||||
let s = cross(sub(c, a), u) / denominator;
|
||||
// Strict interiors: touches, T junctions and intersections at bends are not proper crossings.
|
||||
(t > 1e-9 && t < 1. - 1e-9 && s > 1e-9 && s < 1. - 1e-9)
|
||||
.then_some((a.0 + t * u.0, a.1 + t * u.1))
|
||||
}
|
||||
fn shared_length(a: P, b: P, c: P, d: P) -> f64 {
|
||||
let u = sub(b, a);
|
||||
let len = length(u);
|
||||
if len < EPS || cross(u, sub(c, a)).abs() / len > EPS || cross(u, sub(d, a)).abs() / len > EPS {
|
||||
return 0.;
|
||||
}
|
||||
let t = dot(sub(c, a), u) / len;
|
||||
let s = dot(sub(d, a), u) / len;
|
||||
(t.max(s).min(len) - t.min(s).max(0.)).max(0.)
|
||||
}
|
||||
// Closed-segment point intersections. A positive collinear interval is not a
|
||||
// point: it remains represented by the existing shared-length metric.
|
||||
fn point_contact(a: P, b: P, c: P, d: P) -> Option<P> {
|
||||
let u = sub(b, a);
|
||||
let v = sub(d, c);
|
||||
let on_segment = |at: P, start: P, end: P| {
|
||||
let delta = sub(end, start);
|
||||
let len = length(delta);
|
||||
if len < EPS {
|
||||
return length(sub(at, start)) < EPS;
|
||||
}
|
||||
cross(delta, sub(at, start)).abs() / len <= EPS
|
||||
&& dot(sub(at, start), delta) >= -EPS * len
|
||||
&& dot(sub(at, end), delta) <= EPS * len
|
||||
};
|
||||
if length(u) < EPS {
|
||||
return on_segment(a, c, d).then_some(a);
|
||||
}
|
||||
if length(v) < EPS {
|
||||
return on_segment(c, a, b).then_some(c);
|
||||
}
|
||||
let denominator = cross(u, v);
|
||||
if denominator.abs() < 1e-9 {
|
||||
if shared_length(a, b, c, d) > EPS {
|
||||
return None;
|
||||
}
|
||||
return [a, b, c, d]
|
||||
.into_iter()
|
||||
.find(|at| on_segment(*at, a, b) && on_segment(*at, c, d));
|
||||
}
|
||||
let t = cross(sub(c, a), v) / denominator;
|
||||
let s = cross(sub(c, a), u) / denominator;
|
||||
((-1e-9..=1. + 1e-9).contains(&t) && (-1e-9..=1. + 1e-9).contains(&s))
|
||||
.then_some((a.0 + t.clamp(0., 1.) * u.0, a.1 + t.clamp(0., 1.) * u.1))
|
||||
}
|
||||
fn point_contacts(a: &[P], b: &[P]) -> Vec<(P, bool)> {
|
||||
let mut unique = BTreeMap::new();
|
||||
for ab in a.windows(2) {
|
||||
for cd in b.windows(2) {
|
||||
if let Some(at) = point_contact(ab[0], ab[1], cd[0], cd[1]) {
|
||||
let key = ((at.0 / EPS).round() as i64, (at.1 / EPS).round() as i64);
|
||||
let proper = proper_cross(ab[0], ab[1], cd[0], cd[1]).is_some();
|
||||
let entry = unique.entry(key).or_insert((at, false));
|
||||
entry.1 |= proper;
|
||||
}
|
||||
}
|
||||
}
|
||||
unique.into_values().collect()
|
||||
}
|
||||
fn contact_role(points: &[P], at: P) -> &'static str {
|
||||
if points
|
||||
.first()
|
||||
.into_iter()
|
||||
.chain(points.last())
|
||||
.any(|tip| length(sub(*tip, at)) < EPS)
|
||||
{
|
||||
"route_endpoint"
|
||||
} else if points.iter().any(|vertex| length(sub(*vertex, at)) < EPS) {
|
||||
"internal_vertex"
|
||||
} else {
|
||||
"segment_interior"
|
||||
}
|
||||
}
|
||||
fn ancestor(view: &ProjectedView, owner: Id, mut node: Id) -> bool {
|
||||
for _ in 0..view.nodes.len() {
|
||||
let Some(parent) = view
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|n| n.id == node)
|
||||
.and_then(|n| n.visual_parent)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if parent == owner {
|
||||
return true;
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
false
|
||||
}
|
||||
fn terminal_points(
|
||||
edge: &projection::ProjectedEdge,
|
||||
points: &[Position],
|
||||
segment: usize,
|
||||
) -> Vec<(Id, P)> {
|
||||
let mut owners = Vec::new();
|
||||
if segment == 0 {
|
||||
owners.push((edge.source, p(points[0])));
|
||||
}
|
||||
if segment + 2 == points.len() {
|
||||
owners.push((edge.target, p(*points.last().unwrap())));
|
||||
}
|
||||
owners
|
||||
}
|
||||
fn inside_length(a: P, b: P, r: Rect) -> f64 {
|
||||
let delta = sub(b, a);
|
||||
let mut lo = 0_f64;
|
||||
let mut hi = 1_f64;
|
||||
for (origin, direction, min, max) in [
|
||||
(a.0, delta.0, r.0 + EPS, r.2 - EPS),
|
||||
(a.1, delta.1, r.1 + EPS, r.3 - EPS),
|
||||
] {
|
||||
if min >= max {
|
||||
return 0.;
|
||||
}
|
||||
if direction.abs() < 1e-9 {
|
||||
if origin <= min || origin >= max {
|
||||
return 0.;
|
||||
}
|
||||
} else {
|
||||
let t = (min - origin) / direction;
|
||||
let u = (max - origin) / direction;
|
||||
lo = lo.max(t.min(u));
|
||||
hi = hi.min(t.max(u));
|
||||
}
|
||||
}
|
||||
(hi - lo).max(0.) * length(delta)
|
||||
}
|
||||
fn header_height(project: &Project, diagram: Id, node: &projection::ProjectedNode) -> f64 {
|
||||
let h = if project.diagrams[&diagram]
|
||||
.projection
|
||||
.state_machine()
|
||||
.is_some()
|
||||
{
|
||||
projection::state_header_height(project, node.element)
|
||||
} else {
|
||||
64.
|
||||
};
|
||||
h.min(node.size.height) as f64
|
||||
}
|
||||
|
||||
fn metrics(project: &Project, diagram: Id) -> Value {
|
||||
let view = projection::project_view(project, diagram);
|
||||
let routed = routing::route_diagram(project, &project.diagrams[&diagram], &view);
|
||||
let edges: Vec<_> = routed.edges.values().collect();
|
||||
let definitions: BTreeMap<_, _> = view.edges.iter().map(|e| (e.id, e)).collect();
|
||||
let mut crossings = Vec::new();
|
||||
let mut shared = 0.;
|
||||
let mut excluded_shared = 0.;
|
||||
let mut excluded_stub_crossings = 0;
|
||||
let mut contacts = Vec::new();
|
||||
let mut common_terminal_contacts = 0;
|
||||
for (i, a) in edges.iter().enumerate() {
|
||||
for b in edges.iter().skip(i + 1) {
|
||||
let ap: Vec<_> = a.points.iter().copied().map(p).collect();
|
||||
let bp: Vec<_> = b.points.iter().copied().map(p).collect();
|
||||
let ad = definitions[&a.id];
|
||||
let bd = definitions[&b.id];
|
||||
for (at, proper) in point_contacts(&ap, &bp) {
|
||||
let common_terminal = [(ad.source, ap.first()), (ad.target, ap.last())]
|
||||
.iter()
|
||||
.any(|(owner, tip)| {
|
||||
tip.is_some_and(|tip| length(sub(*tip, at)) < EPS)
|
||||
&& [(bd.source, bp.first()), (bd.target, bp.last())]
|
||||
.iter()
|
||||
.any(|(other, tip)| {
|
||||
owner == other
|
||||
&& tip.is_some_and(|tip| length(sub(*tip, at)) < EPS)
|
||||
})
|
||||
});
|
||||
common_terminal_contacts += usize::from(common_terminal);
|
||||
contacts.push(json!({"edges":[a.id,b.id],"at":[at.0,at.1],
|
||||
"proper_crossing":proper,"roles":[contact_role(&ap,at),contact_role(&bp,at)],
|
||||
"common_physical_terminal":common_terminal}));
|
||||
}
|
||||
let mut unique = BTreeSet::new();
|
||||
for (ai, ab) in a.points.windows(2).enumerate() {
|
||||
for (bi, cd) in b.points.windows(2).enumerate() {
|
||||
let mut common_tips = Vec::new();
|
||||
for (owner, tip) in terminal_points(definitions[&a.id], &a.points, ai) {
|
||||
if terminal_points(definitions[&b.id], &b.points, bi)
|
||||
.iter()
|
||||
.any(|(other, at)| *other == owner && length(sub(*at, tip)) < EPS)
|
||||
{
|
||||
common_tips.push(tip);
|
||||
}
|
||||
}
|
||||
let crossing = proper_cross(p(ab[0]), p(ab[1]), p(cd[0]), p(cd[1]));
|
||||
let overlap = shared_length(p(ab[0]), p(ab[1]), p(cd[0]), p(cd[1]));
|
||||
// Raw totals stay primary. Only physically common tips get
|
||||
// bounded PORT_STUB exemptions, never a whole compacted segment.
|
||||
shared += overlap;
|
||||
excluded_shared +=
|
||||
overlap.min(common_tips.len() as f64 * routing::PORT_STUB as f64);
|
||||
if let Some(at) = crossing
|
||||
&& unique.insert(((at.0 / EPS).round() as i64, (at.1 / EPS).round() as i64))
|
||||
{
|
||||
let near_tip = common_tips
|
||||
.iter()
|
||||
.any(|tip| length(sub(at, *tip)) <= routing::PORT_STUB as f64 + EPS);
|
||||
excluded_stub_crossings += usize::from(near_tip);
|
||||
crossings.push(json!({"edges":[a.id,b.id],"at":[at.0,at.1],"within_common_terminal_stub":near_tip}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut node_collisions = Vec::new();
|
||||
let mut label_nodes = Vec::new();
|
||||
let mut label_labels = Vec::new();
|
||||
let mut excluded_ancestor_labels = 0;
|
||||
let mut penetrations = Vec::new();
|
||||
let mut label_strokes = Vec::new();
|
||||
for e in &edges {
|
||||
let def = definitions[&e.id];
|
||||
for n in &view.nodes {
|
||||
if n.id == def.source || n.id == def.target {
|
||||
continue;
|
||||
}
|
||||
let mut obstacle = rect(n.position, n.size);
|
||||
let ancestor_header =
|
||||
ancestor(&view, n.id, def.source) || ancestor(&view, n.id, def.target);
|
||||
if ancestor_header {
|
||||
obstacle.3 = obstacle.1 + header_height(project, diagram, n);
|
||||
}
|
||||
let length: f64 = e
|
||||
.points
|
||||
.windows(2)
|
||||
.map(|w| inside_length(p(w[0]), p(w[1]), obstacle))
|
||||
.sum();
|
||||
if length > EPS {
|
||||
penetrations.push(json!({"edge":e.id,"node":n.id,"length":length,"ancestor_header_only":ancestor_header}));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i, a) in view.nodes.iter().enumerate() {
|
||||
for b in view.nodes.iter().skip(i + 1) {
|
||||
let area = overlap(rect(a.position, a.size), rect(b.position, b.size));
|
||||
if area > 0. && !ancestor(&view, a.id, b.id) && !ancestor(&view, b.id, a.id) {
|
||||
node_collisions.push(json!({"nodes":[a.id,b.id],"intersection_area":area}));
|
||||
}
|
||||
}
|
||||
}
|
||||
let labels: Vec<_> = edges.iter().filter(|e| !e.label.text.is_empty()).collect();
|
||||
for (i, e) in labels.iter().enumerate() {
|
||||
let lb = rect(e.label.bounds.position, e.label.bounds.size);
|
||||
let def = definitions[&e.id];
|
||||
for n in &view.nodes {
|
||||
let nb = rect(n.position, n.size);
|
||||
let area = overlap(lb, nb);
|
||||
if area == 0. {
|
||||
continue;
|
||||
}
|
||||
let body = (nb.0, nb.1 + header_height(project, diagram, n), nb.2, nb.3);
|
||||
if contains(body, lb)
|
||||
&& (ancestor(&view, n.id, def.source) || ancestor(&view, n.id, def.target))
|
||||
{
|
||||
excluded_ancestor_labels += 1;
|
||||
} else {
|
||||
label_nodes.push(json!({"edge":e.id,"node":n.id,"intersection_area":area}));
|
||||
}
|
||||
}
|
||||
for other in labels.iter().skip(i + 1) {
|
||||
let area = overlap(
|
||||
lb,
|
||||
rect(other.label.bounds.position, other.label.bounds.size),
|
||||
);
|
||||
if area > 0. {
|
||||
label_labels.push(json!({"edges":[e.id,other.id],"intersection_area":area}));
|
||||
}
|
||||
}
|
||||
for other in edges.iter().filter(|other| other.id != e.id) {
|
||||
let length: f64 = other
|
||||
.points
|
||||
.windows(2)
|
||||
.map(|w| inside_length(p(w[0]), p(w[1]), lb))
|
||||
.sum();
|
||||
if length > EPS {
|
||||
label_strokes
|
||||
.push(json!({"label_edge":e.id,"stroke_edge":other.id,"length":length}));
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut total_length = 0.;
|
||||
let mut bends = 0;
|
||||
for e in &edges {
|
||||
total_length += e
|
||||
.points
|
||||
.windows(2)
|
||||
.map(|w| length(sub(p(w[1]), p(w[0]))))
|
||||
.sum::<f64>();
|
||||
bends += e
|
||||
.points
|
||||
.windows(3)
|
||||
.filter(|w| {
|
||||
let a = sub(p(w[1]), p(w[0]));
|
||||
let b = sub(p(w[2]), p(w[1]));
|
||||
length(a) > EPS && length(b) > EPS && (cross(a, b).abs() > EPS || dot(a, b) < 0.)
|
||||
})
|
||||
.count();
|
||||
}
|
||||
let warnings: Vec<_> = edges
|
||||
.iter()
|
||||
.flat_map(|e| {
|
||||
e.warnings
|
||||
.iter()
|
||||
.map(move |w| json!({"edge":e.id,"warning":format!("{w:?}")}))
|
||||
})
|
||||
.collect();
|
||||
json!({
|
||||
"nodes":view.nodes.len(),"edges":edges.len(),"ports":view.ports.len(),
|
||||
"proper_crossings":crossings.len(),"crossing_details":crossings,
|
||||
"point_contacts":contacts.len(),"point_contact_details":contacts,
|
||||
"common_physical_terminal_point_contacts":common_terminal_contacts,
|
||||
"pairwise_collinear_shared_length":shared,
|
||||
"excluded_common_terminal_shared_length":excluded_shared,"excluded_common_terminal_crossings":excluded_stub_crossings,
|
||||
"nonterminal_proper_crossings":crossings.len()-excluded_stub_crossings,
|
||||
"nonterminal_pairwise_shared_length":shared-excluded_shared,
|
||||
"unrelated_edge_node_penetrations":penetrations.len(),"edge_node_details":penetrations,
|
||||
"unrelated_label_stroke_intersections":label_strokes.len(),"label_stroke_details":label_strokes,
|
||||
"unrelated_node_collisions":node_collisions.len(),"node_collision_details":node_collisions,
|
||||
"label_node_collisions":label_nodes.len(),"label_node_details":label_nodes,
|
||||
"excluded_contained_endpoint_ancestor_label_pairs":excluded_ancestor_labels,
|
||||
"label_label_collisions":label_labels.len(),"label_label_details":label_labels,
|
||||
"warning_count":warnings.len(),"warnings":warnings,
|
||||
"drawing_bounds":{"position":routed.bounds.position,"size":routed.bounds.size},
|
||||
"drawing_area":routed.bounds.size.width as f64*routed.bounds.size.height as f64,
|
||||
"route_bends":bends,"route_length":total_length,
|
||||
"projected_nodes":view.nodes,"projected_ports":view.ports,
|
||||
"route_endpoints":edges.iter().map(|e|json!({"id":e.id,
|
||||
"source_owner":definitions[&e.id].source,"target_owner":definitions[&e.id].target,
|
||||
"source":e.points.first(),"target":e.points.last()})).collect::<Vec<_>>(),
|
||||
"routed_edges":edges.iter().map(|e|json!({"id":e.id,"points":e.points,"label":{
|
||||
"text":e.label.text,"position":e.label.bounds.position,"size":e.label.bounds.size}})).collect::<Vec<_>>()
|
||||
})
|
||||
}
|
||||
|
||||
struct Builder {
|
||||
project: Project,
|
||||
diagram: Id,
|
||||
next: u128,
|
||||
witness: Option<Project>,
|
||||
}
|
||||
impl Builder {
|
||||
fn new(name: &str) -> Self {
|
||||
let mut project = Project::empty();
|
||||
project.id = Id::from_u128(90_000);
|
||||
project.alias = "layout_probe".into();
|
||||
project.name = name.into();
|
||||
let old = project.ensure_diagram(Layer::Sa);
|
||||
let diagram = Id::from_u128(90_001);
|
||||
reidentify(&mut project, old, diagram).unwrap();
|
||||
project.diagrams.get_mut(&diagram).unwrap().projection = ProjectionKind::FunctionalDataflow;
|
||||
Self {
|
||||
project,
|
||||
diagram,
|
||||
next: 1,
|
||||
witness: None,
|
||||
}
|
||||
}
|
||||
fn stable(&mut self, old: Id) -> Id {
|
||||
let id = Id::from_u128(self.next);
|
||||
self.next += 1;
|
||||
reidentify(&mut self.project, old, id).unwrap();
|
||||
id
|
||||
}
|
||||
fn function(&mut self, name: &str, parent: Option<Id>, x: f32, y: f32) -> Id {
|
||||
let old = self
|
||||
.project
|
||||
.add_element(Kind::Function, Layer::Sa, name, parent)
|
||||
.unwrap();
|
||||
let id = self.stable(old);
|
||||
let old = self.project.place(self.diagram, id, Position { x, y });
|
||||
self.stable(old);
|
||||
id
|
||||
}
|
||||
fn exchange(&mut self, name: &str, a: Id, b: Id) -> Id {
|
||||
let old = self
|
||||
.project
|
||||
.relate(RelationKind::FunctionalExchange, name, a, b);
|
||||
let edge = self.stable(old);
|
||||
let RelationBody::FunctionalExchange {
|
||||
source_port,
|
||||
target_port,
|
||||
..
|
||||
} = self.project.relations[&edge].body
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
for (old, prefix) in [(source_port, "out"), (target_port, "in")] {
|
||||
let id = self.stable(old);
|
||||
self.project.elements.get_mut(&id).unwrap().alias =
|
||||
format!("{prefix}_{}", id.as_u128());
|
||||
}
|
||||
edge
|
||||
}
|
||||
fn node(&self, element: Id) -> Id {
|
||||
self.project.diagrams[&self.diagram]
|
||||
.nodes
|
||||
.values()
|
||||
.find(|n| n.element == element)
|
||||
.unwrap()
|
||||
.id
|
||||
}
|
||||
}
|
||||
fn fixtures() -> Vec<(&'static str, Builder)> {
|
||||
let mut all = Vec::new();
|
||||
for (name, count) in [("flat_chain_4", 4), ("chain_7_row_wrap", 7)] {
|
||||
let mut f = Builder::new(name);
|
||||
let mut nodes = Vec::new();
|
||||
for i in 0..count {
|
||||
nodes.push(f.function(&format!("Function {i}"), None, 40. + 320. * i as f32, 80.));
|
||||
}
|
||||
for i in 0..count - 1 {
|
||||
f.exchange(&format!("Flow {i}"), nodes[i], nodes[i + 1]);
|
||||
}
|
||||
all.push((name, f));
|
||||
}
|
||||
for (name, links) in [
|
||||
("diamond", vec![(0, 1), (0, 2), (1, 3), (2, 3)]),
|
||||
("crossed_bipartite", vec![(0, 3), (1, 2), (0, 2), (1, 3)]),
|
||||
] {
|
||||
let mut f = Builder::new(name);
|
||||
let mut nodes = Vec::new();
|
||||
let coordinates = if name == "diamond" {
|
||||
[(40., 240.), (400., 80.), (400., 400.), (760., 240.)]
|
||||
} else {
|
||||
[(40., 80.), (40., 400.), (620., 80.), (620., 400.)]
|
||||
};
|
||||
for (i, (x, y)) in coordinates.into_iter().enumerate() {
|
||||
nodes.push(f.function(&format!("Node {i}"), None, x, y));
|
||||
}
|
||||
for (i, (a, b)) in links.into_iter().enumerate() {
|
||||
f.exchange(&format!("Flow {i}"), nodes[a], nodes[b]);
|
||||
}
|
||||
all.push((name, f));
|
||||
}
|
||||
let mut f = Builder::new("nested_cross_boundary");
|
||||
let group = f.function("Parent function", None, 40., 40.);
|
||||
let a = f.function("Child send", Some(group), 100., 130.);
|
||||
let b = f.function("Child receive", Some(group), 100., 330.);
|
||||
let c = f.function("Outside", None, 900., 210.);
|
||||
f.exchange("Internal flow", a, b);
|
||||
f.exchange("Cross boundary", b, c);
|
||||
all.push(("nested_cross_boundary", f));
|
||||
for fixed in [false, true] {
|
||||
let name = if fixed {
|
||||
"fixed_ports"
|
||||
} else {
|
||||
"authored_detour_and_label"
|
||||
};
|
||||
let mut f = Builder::new(name);
|
||||
let a = f.function("Sender", None, 40., 80.);
|
||||
let b = f.function("Receiver", None, 640., 80.);
|
||||
let edge = f.exchange("Preserved information", a, b);
|
||||
if fixed {
|
||||
let RelationBody::FunctionalExchange {
|
||||
source_port,
|
||||
target_port,
|
||||
..
|
||||
} = f.project.relations[&edge].body
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
for (element, port, side, offset) in [
|
||||
(a, source_port, PortAnchorSide::Left, 0.3),
|
||||
(b, target_port, PortAnchorSide::Right, 0.7),
|
||||
] {
|
||||
let node = f.node(element);
|
||||
f.project = prepare_command(
|
||||
&f.project,
|
||||
&Command::SetPortAnchor {
|
||||
diagram: f.diagram,
|
||||
node,
|
||||
anchor: PortAnchor { port, side, offset },
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
.project;
|
||||
}
|
||||
} else {
|
||||
f.project
|
||||
.diagrams
|
||||
.get_mut(&f.diagram)
|
||||
.unwrap()
|
||||
.routes
|
||||
.push(EdgeRoute {
|
||||
edge,
|
||||
source_attachment: None,
|
||||
target_attachment: None,
|
||||
waypoints: vec![
|
||||
Position { x: 400., y: -320. },
|
||||
Position { x: 1000., y: -320. },
|
||||
Position { x: 1000., y: 240. },
|
||||
],
|
||||
label: Some(EdgeLabel {
|
||||
fraction: 0.7,
|
||||
offset: Position { x: 100., y: -180. },
|
||||
}),
|
||||
});
|
||||
}
|
||||
all.push((name, f));
|
||||
}
|
||||
let mut f = Builder::new("two_containers_reversed_children");
|
||||
let left = f.function("Left group", None, 40., 40.);
|
||||
let right = f.function("Right group", None, 820., 40.);
|
||||
let la = f.function("Left A", Some(left), 100., 130.);
|
||||
let lb = f.function("Left B", Some(left), 100., 330.);
|
||||
let ra = f.function("Right A", Some(right), 880., 130.);
|
||||
let rb = f.function("Right B", Some(right), 880., 330.);
|
||||
f.exchange("Upper to lower", la, rb);
|
||||
f.exchange("Lower to upper", lb, ra);
|
||||
let mut witness = f.project.clone();
|
||||
for (element, y) in [(ra, 330.), (rb, 130.)] {
|
||||
let node = f.node(element);
|
||||
witness
|
||||
.diagrams
|
||||
.get_mut(&f.diagram)
|
||||
.unwrap()
|
||||
.nodes
|
||||
.get_mut(&node)
|
||||
.unwrap()
|
||||
.position
|
||||
.y = y;
|
||||
}
|
||||
f.witness = Some(witness);
|
||||
all.push(("two_containers_reversed_children", f));
|
||||
let mut f = Builder::new("long_ordinary_labels");
|
||||
let a = f.function("Input", None, 40., 100.);
|
||||
let b = f.function("Transform", None, 400., 100.);
|
||||
let c = f.function("Output", None, 760., 100.);
|
||||
f.exchange(
|
||||
"A very long first information exchange label exceeding the ordinary cutoff",
|
||||
a,
|
||||
b,
|
||||
);
|
||||
f.exchange(
|
||||
"A very long second information exchange label exceeding the ordinary cutoff",
|
||||
b,
|
||||
c,
|
||||
);
|
||||
f.exchange(
|
||||
"A very long bypass information exchange label exceeding the ordinary cutoff",
|
||||
a,
|
||||
c,
|
||||
);
|
||||
all.push(("long_ordinary_labels", f));
|
||||
all
|
||||
}
|
||||
|
||||
fn reset_effective_routes(project: &Project, diagram: Id) -> Project {
|
||||
let view = projection::project_view(project, diagram);
|
||||
let routed = routing::route_diagram(project, &project.diagrams[&diagram], &view);
|
||||
let mut reset = project.clone();
|
||||
for route in &mut reset.diagrams.get_mut(&diagram).unwrap().routes {
|
||||
if routed
|
||||
.edges
|
||||
.get(&route.edge)
|
||||
.is_some_and(|edge| !edge.custom_suspended)
|
||||
{
|
||||
route.waypoints.clear();
|
||||
route.label = None;
|
||||
}
|
||||
}
|
||||
reset
|
||||
}
|
||||
|
||||
fn conservation(before: &Project, after: &Project, diagram: Id) -> Value {
|
||||
let mut semantic = after.clone();
|
||||
semantic.diagrams = before.diagrams.clone();
|
||||
let bd = &before.diagrams[&diagram];
|
||||
let ad = &after.diagrams[&diagram];
|
||||
let mut stable_view = ad.clone();
|
||||
stable_view.nodes = bd.nodes.clone();
|
||||
stable_view.routes = bd.routes.clone();
|
||||
stable_view.layout = bd.layout.clone();
|
||||
let mut other_views = after.diagrams.clone();
|
||||
other_views.insert(diagram, bd.clone());
|
||||
let node_metadata = bd.nodes.len() == ad.nodes.len()
|
||||
&& bd.nodes.iter().all(|(id, node)| {
|
||||
ad.nodes.get(id).is_some_and(|new| {
|
||||
let mut restored = new.clone();
|
||||
restored.position = node.position;
|
||||
restored.size = node.size;
|
||||
restored == *node
|
||||
})
|
||||
});
|
||||
json!({"semantic_records_exact":semantic==*before,"target_view_nongeometry_exact":stable_view==*bd,
|
||||
"other_views_exact":other_views==before.diagrams,"node_identity_visibility_anchors_exact":node_metadata,
|
||||
"authored_routes_exact":ad.routes==bd.routes})
|
||||
}
|
||||
|
||||
fn roundtrip(project: &Project) -> Value {
|
||||
let bytes = serde_json::to_vec(project).unwrap();
|
||||
let json_result = persistence::decode(&bytes);
|
||||
let source = language::format(project);
|
||||
let source_result = language::parse(&source);
|
||||
json!({"json_exact":json_result.as_ref().is_ok_and(|p|p==project),
|
||||
"json_error":json_result.err().map(|e|e.to_string()),
|
||||
"single_source_exact":source_result.as_ref().is_ok_and(|p|p==project),
|
||||
"source_error":source_result.err().map(|e|format!("{e:?}"))})
|
||||
}
|
||||
fn observe(name: &str, f: Builder) -> Value {
|
||||
let witness = f.witness;
|
||||
let before = f.project;
|
||||
let diagram = f.diagram;
|
||||
if let Err(error) = validate_candidate(&before) {
|
||||
return json!({"fixture":name,"fixture_error":error.to_string()});
|
||||
}
|
||||
let mut session = Session::new(before.clone());
|
||||
if let Err(error) = session.execute(Command::Layout(diagram)) {
|
||||
return json!({"fixture":name,"before":metrics(&before,diagram),"layout_error":error.to_string()});
|
||||
}
|
||||
let after = session.project().clone();
|
||||
let changed = after != before;
|
||||
let had_undo = session.can_undo();
|
||||
session.undo();
|
||||
let undo = session.project() == &before;
|
||||
let one_step = !session.can_undo();
|
||||
session.redo();
|
||||
let redo = session.project() == &after;
|
||||
let second = prepare_command(&after, &Command::Layout(diagram));
|
||||
let reset = reset_effective_routes(&after, diagram);
|
||||
let mut repeated = after.clone();
|
||||
let mut stability = Vec::new();
|
||||
for pass in 2..=10 {
|
||||
match prepare_command(&repeated, &Command::Layout(diagram)) {
|
||||
Ok(next) => {
|
||||
stability.push(json!({"pass":pass,"equal_previous":next.project==repeated,"equal_first":next.project==after}));
|
||||
repeated = next.project;
|
||||
}
|
||||
Err(error) => {
|
||||
stability.push(json!({"pass":pass,"error":error.to_string()}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let witness=witness.map(|p|json!({"metrics":metrics(&p,diagram),"project":p,
|
||||
"conservation":conservation(&before,&p,diagram),"validation_error":validate_candidate(&p).err().map(|e|e.to_string())}));
|
||||
let candidate = match layered::candidate(&before, diagram) {
|
||||
Err(error) => json!({"supported":false,"error":error.to_string()}),
|
||||
Ok(candidate) => {
|
||||
if let Err(error) = validate_candidate(&candidate) {
|
||||
json!({"supported":true,"validation_error":error.to_string(),"project":candidate})
|
||||
} else {
|
||||
let again = layered::candidate(&candidate, diagram);
|
||||
let duplicate = layered::candidate(&before, diagram);
|
||||
let mut repeated_candidate = candidate.clone();
|
||||
let mut candidate_stability = Vec::new();
|
||||
for pass in 2..=10 {
|
||||
match layered::candidate(&repeated_candidate, diagram) {
|
||||
Ok(next) => {
|
||||
candidate_stability.push(json!({"pass":pass,"equal_previous":next==repeated_candidate,"equal_first":next==candidate}));
|
||||
repeated_candidate = next;
|
||||
}
|
||||
Err(error) => {
|
||||
candidate_stability
|
||||
.push(json!({"pass":pass,"error":error.to_string()}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
json!({"supported":true,"metrics":metrics(&candidate,diagram),"project":candidate,
|
||||
"conservation":conservation(&before,&candidate,diagram),"roundtrip":roundtrip(&candidate),
|
||||
"ten_candidate_calls":candidate_stability,
|
||||
"repeat_same_input_exact":duplicate.as_ref().is_ok_and(|p|*p==candidate),
|
||||
"idempotent":again.as_ref().is_ok_and(|p|*p==candidate),
|
||||
"repeat_error":duplicate.err().map(|e|e.to_string()),"idempotence_error":again.err().map(|e|e.to_string())})
|
||||
}
|
||||
}
|
||||
};
|
||||
json!({"fixture":name,"diagram":diagram,"before":metrics(&before,diagram),"after":metrics(&after,diagram),
|
||||
"before_project":before,"after_project":after,"conservation":conservation(&before,&after,diagram),
|
||||
"reset_only_control":{"metrics":metrics(&reset,diagram),"project":reset,"conservation":conservation(&before,&reset,diagram),"roundtrip":roundtrip(&reset)},
|
||||
"manual_planar_order_witness":witness,"ten_layout_calls":stability,"experimental_candidate":candidate,
|
||||
"checks":{
|
||||
"changed":changed,"history_entry_matches_change":had_undo==changed,"undo_exact":undo,"one_step_undo":one_step,"redo_exact":redo,
|
||||
"second_layout_exact":second.as_ref().is_ok_and(|s|s.project==after),"second_layout_error":second.err().map(|e|e.to_string()),
|
||||
"before_roundtrip":roundtrip(&before),"after_roundtrip":roundtrip(&after)}})
|
||||
}
|
||||
fn main() {
|
||||
// Analytic checks validate the observer, not any layout's quality.
|
||||
let horizontal = [(0., 0.), (10., 0.)];
|
||||
assert_eq!(
|
||||
point_contacts(&horizontal, &[(5., -5.), (5., 5.)]),
|
||||
vec![((5., 0.), true)]
|
||||
);
|
||||
assert_eq!(
|
||||
point_contacts(&horizontal, &[(5., 0.), (5., 5.)]),
|
||||
vec![((5., 0.), false)]
|
||||
);
|
||||
let bend = [(5., -5.), (5., 0.), (8., 3.)];
|
||||
assert_eq!(point_contacts(&horizontal, &bend), vec![((5., 0.), false)]);
|
||||
assert_eq!(contact_role(&bend, (5., 0.)), "internal_vertex");
|
||||
assert_eq!(contact_role(&horizontal, (5., 0.)), "segment_interior");
|
||||
assert_eq!(
|
||||
point_contacts(&horizontal, &[(10., 0.), (10., 5.)]),
|
||||
vec![((10., 0.), false)]
|
||||
);
|
||||
assert_eq!(contact_role(&horizontal, (10., 0.)), "route_endpoint");
|
||||
assert_eq!(
|
||||
point_contacts(&horizontal, &[(10., 0.), (20., 0.)]),
|
||||
vec![((10., 0.), false)]
|
||||
);
|
||||
assert!(point_contacts(&horizontal, &[(4., 0.), (12., 0.)]).is_empty());
|
||||
assert_eq!(
|
||||
proper_cross((0., 0.), (10., 0.), (5., -5.), (5., 5.)),
|
||||
Some((5., 0.))
|
||||
);
|
||||
assert_eq!(
|
||||
proper_cross((0., 0.), (10., 0.), (10., 0.), (10., 5.)),
|
||||
None
|
||||
);
|
||||
assert!((shared_length((0., 0.), (10., 0.), (4., 0.), (12., 0.)) - 6.).abs() < EPS);
|
||||
assert_eq!(shared_length((0., 0.), (10., 0.), (4., 1.), (12., 1.)), 0.);
|
||||
assert_eq!(overlap((0., 0., 10., 10.), (10., 0., 20., 10.)), 0.);
|
||||
assert!((inside_length((0., 5.), (10., 5.), (2., 2., 8., 8.)) - 6.).abs() < 3. * EPS);
|
||||
assert_eq!(inside_length((0., 2.), (10., 2.), (2., 2., 8., 8.)), 0.);
|
||||
println!(
|
||||
"{}",
|
||||
json!({"probe":"auto_layout_probe_v2","reference_source":"715036e132677dd2bc2fb37ed316d93dc9987aec","metric_selfchecks":"passed", "quality_thresholds":null,
|
||||
"point_contact_definition":"Unexempted unique point per edge pair (EPS quantization), closed segments, proper-crossing flag ORed across segment witnesses; roles distinguish route endpoints/internal vertices/interiors. Positive collinear intervals are only in shared-length metric; a noncollinear witness at an overlap boundary is still a point contact. Common physical terminal requires equal owner and equal endpoint coordinate and is classified, never subtracted. Route endpoints emitted for exact comparison against the frozen prior run, not assumed invariant across node layout.",
|
||||
"exclusions":"Raw strict-interior crossings and pairwise shared length are primary; separately bound common physical endpoint exclusions to PORT_STUB. Ancestor node containment excluded. Labels wholly inside endpoint-ancestor BODY below header exempt; headers retained. Penetration excludes endpoint nodes and endpoint-ancestor bodies. Label/stroke excludes own edge. Core approximate label bounds, no glyph/port-label metrics."})
|
||||
);
|
||||
for (name, f) in fixtures() {
|
||||
println!("{}", observe(name, f));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
//! Isolated #32 experiment, not a production layout engine.
|
||||
//! Uses existing Layout sizing, three deterministic ordering passes, and one
|
||||
//! core-estimated-label spacing pass. Automatic elbows remain derived. Folded/omitted
|
||||
//! node topology is explicitly unsupported; filtered edges retain their metadata.
|
||||
use oa_core::{Command, Id, ModelError, Position, Project, Size, projection, routing};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
const WORK_LIMIT: usize = 200_000;
|
||||
const NODE_LIMIT: usize = 256;
|
||||
const EDGE_LIMIT: usize = 1024;
|
||||
|
||||
fn spend(work: &mut usize) -> Result<(), ModelError> {
|
||||
*work += 1;
|
||||
if *work > WORK_LIMIT {
|
||||
return Err(ModelError("Layered probe work limit exceeded.".into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return a new Project; caller owns comparison, history and serialization.
|
||||
pub fn candidate(project: &Project, diagram: Id) -> Result<Project, ModelError> {
|
||||
let original = project
|
||||
.diagrams
|
||||
.get(&diagram)
|
||||
.ok_or_else(|| ModelError("Missing probe diagram.".into()))?;
|
||||
let view = projection::project_diagram(project, original);
|
||||
if view.nodes.len() > NODE_LIMIT || view.edges.len() > EDGE_LIMIT {
|
||||
return Err(ModelError("Layered probe graph limit exceeded.".into()));
|
||||
}
|
||||
if view.nodes.len() != original.nodes.len() || view.nodes.iter().any(|n| n.collapsed) {
|
||||
return Err(ModelError(
|
||||
"Layered probe does not support folded/omitted node topology.".into(),
|
||||
));
|
||||
}
|
||||
let routed = routing::route_diagram(project, original, &view);
|
||||
let eligible: BTreeSet<_> = view
|
||||
.edges
|
||||
.iter()
|
||||
.filter(|edge| {
|
||||
projection::edge_endpoint_placements(project, original, edge.id)
|
||||
== Some((edge.source, edge.target))
|
||||
&& routed
|
||||
.edges
|
||||
.get(&edge.id)
|
||||
.is_some_and(|route| !route.custom_suspended)
|
||||
})
|
||||
.map(|edge| edge.id)
|
||||
.collect();
|
||||
let mut result = oa_core::prepare_command(project, &Command::Layout(diagram))?.project;
|
||||
// Discard baseline route translation: final routes are reconstructed directly
|
||||
// from original geometry, avoiding two translations and preserving list order.
|
||||
result.diagrams.get_mut(&diagram).unwrap().routes = original.routes.clone();
|
||||
for route in &mut result.diagrams.get_mut(&diagram).unwrap().routes {
|
||||
if eligible.contains(&route.edge) {
|
||||
route.waypoints.clear();
|
||||
route.label = None;
|
||||
}
|
||||
}
|
||||
let baseline = projection::project_view(&result, diagram);
|
||||
let labels = routing::route_diagram(&result, &result.diagrams[&diagram], &baseline);
|
||||
let mut gap_x = 64.0_f32;
|
||||
let mut gap_y = 32.0_f32;
|
||||
for edge in labels.edges.values() {
|
||||
gap_x = gap_x.max(edge.label.bounds.size.width + 24.0);
|
||||
gap_y = gap_y.max(edge.label.bounds.size.height + 24.0);
|
||||
if let Some(relation) = result.relations.get(&edge.id) {
|
||||
for end in routing::association_end_geometry(relation, edge) {
|
||||
gap_x = gap_x.max(end.label.bounds.size.width + 24.0);
|
||||
gap_y = gap_y.max(end.label.bounds.size.height + 24.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !gap_x.is_finite() || !gap_y.is_finite() {
|
||||
return Err(ModelError("Nonfinite estimated label bound.".into()));
|
||||
}
|
||||
let parents: BTreeMap<_, _> = baseline
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n| (n.id, n.visual_parent))
|
||||
.collect();
|
||||
let mut children: BTreeMap<Option<Id>, Vec<Id>> = BTreeMap::new();
|
||||
for node in &baseline.nodes {
|
||||
children
|
||||
.entry(node.visual_parent)
|
||||
.or_default()
|
||||
.push(node.id);
|
||||
}
|
||||
let names: BTreeMap<_, _> = baseline
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n| (n.id, (result.elements[&n.element].alias.clone(), n.id)))
|
||||
.collect();
|
||||
for siblings in children.values_mut() {
|
||||
siblings.sort_by_key(|id| names[id].clone());
|
||||
}
|
||||
let minima: BTreeMap<_, _> = baseline.nodes.iter().map(|n| (n.id, n.size)).collect();
|
||||
let headers: BTreeMap<_, _> = baseline
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n| {
|
||||
(
|
||||
n.id,
|
||||
if original.projection.state_machine().is_some() {
|
||||
projection::state_header_height(&result, n.element)
|
||||
} else {
|
||||
64.0
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let mut positions: BTreeMap<_, _> = baseline.nodes.iter().map(|n| (n.id, n.position)).collect();
|
||||
let mut sizes = minima.clone();
|
||||
let mut work = 0;
|
||||
let mut group_order: Vec<_> = children.keys().copied().collect();
|
||||
group_order.sort_by_key(|parent| {
|
||||
parent.map_or(0, |id| {
|
||||
baseline.nodes.iter().find(|n| n.id == id).unwrap().depth + 1
|
||||
})
|
||||
});
|
||||
let mut groups = BTreeMap::new();
|
||||
for pass in 0..3 {
|
||||
for parent in &group_order {
|
||||
let siblings = &children[parent];
|
||||
let mut arcs = BTreeSet::new();
|
||||
for edge in &baseline.edges {
|
||||
spend(&mut work)?;
|
||||
let a = child_under(edge.source, *parent, &parents, &mut work)?;
|
||||
let b = child_under(edge.target, *parent, &parents, &mut work)?;
|
||||
if edge.oriented
|
||||
&& let (Some(a), Some(b)) = (a, b)
|
||||
&& a != b
|
||||
{
|
||||
arcs.insert((a, b));
|
||||
}
|
||||
}
|
||||
let ranks = ranks(siblings, &arcs, &mut work)?;
|
||||
let mut layers: BTreeMap<usize, Vec<Id>> = BTreeMap::new();
|
||||
for id in siblings {
|
||||
layers.entry(ranks[id]).or_default().push(*id);
|
||||
}
|
||||
// Boundary neighbours participate even though they are not siblings.
|
||||
// Incoming preference anchors the downstream order to its upstream
|
||||
// counterpart instead of swapping both sides simultaneously.
|
||||
let mut scores = BTreeMap::new();
|
||||
for id in siblings {
|
||||
let mut incoming = Vec::new();
|
||||
for edge in &baseline.edges {
|
||||
spend(&mut work)?;
|
||||
let a = child_under(edge.source, *parent, &parents, &mut work)?;
|
||||
let b = child_under(edge.target, *parent, &parents, &mut work)?;
|
||||
if edge.oriented && b == Some(*id) && a != Some(*id) {
|
||||
incoming.push(positions[&edge.source].y + sizes[&edge.source].height / 2.0);
|
||||
}
|
||||
}
|
||||
// Do not also chase outgoing boundary neighbours: simultaneous
|
||||
// swaps in two connected containers can preserve the crossing.
|
||||
let values = &incoming;
|
||||
let score = if values.is_empty() {
|
||||
positions[id].y
|
||||
} else {
|
||||
values.iter().sum::<f32>() / values.len() as f32
|
||||
};
|
||||
scores.insert(*id, score);
|
||||
}
|
||||
for layer in layers.values_mut() {
|
||||
// First pass starts from canonical alias order; subsequent passes
|
||||
// retain a deterministic alias tie break, never hash iteration.
|
||||
if pass > 0 {
|
||||
layer.sort_by(|a, b| {
|
||||
scores[a]
|
||||
.total_cmp(&scores[b])
|
||||
.then_with(|| names[a].cmp(&names[b]))
|
||||
});
|
||||
}
|
||||
}
|
||||
groups.insert(*parent, layers.into_values().collect::<Vec<_>>());
|
||||
}
|
||||
// Recompute from frozen minima, never add spacing to last pass's size.
|
||||
sizes = minima.clone();
|
||||
measure(None, &groups, &headers, &mut sizes, gap_x, gap_y, &mut work)?;
|
||||
place(
|
||||
None,
|
||||
Position { x: 40.0, y: 40.0 },
|
||||
&groups,
|
||||
&headers,
|
||||
&sizes,
|
||||
&mut positions,
|
||||
gap_x,
|
||||
gap_y,
|
||||
&mut work,
|
||||
)?;
|
||||
}
|
||||
let d = result.diagrams.get_mut(&diagram).unwrap();
|
||||
for (id, node) in &mut d.nodes {
|
||||
node.position = positions[id];
|
||||
node.size = sizes[id];
|
||||
}
|
||||
let deltas: BTreeMap<_, _> = original
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|(id, node)| {
|
||||
(
|
||||
*id,
|
||||
Position {
|
||||
x: positions[id].x - node.position.x,
|
||||
y: positions[id].y - node.position.y,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let translated: BTreeMap<_, _> = projection::translated_routes(project, original, &deltas)
|
||||
.into_iter()
|
||||
.map(|r| (r.edge, r))
|
||||
.collect();
|
||||
d.routes = original
|
||||
.routes
|
||||
.iter()
|
||||
.map(|route| {
|
||||
let mut route = translated.get(&route.edge).unwrap_or(route).clone();
|
||||
if eligible.contains(&route.edge) {
|
||||
route.waypoints.clear();
|
||||
route.label = None;
|
||||
}
|
||||
route
|
||||
})
|
||||
.collect();
|
||||
if d.nodes.values().any(|n| {
|
||||
!n.position.x.is_finite()
|
||||
|| !n.position.y.is_finite()
|
||||
|| !n.size.width.is_finite()
|
||||
|| !n.size.height.is_finite()
|
||||
|| n.size.width <= 0.0
|
||||
|| n.size.height <= 0.0
|
||||
}) {
|
||||
return Err(ModelError("Invalid layered probe geometry.".into()));
|
||||
}
|
||||
oa_core::validate_candidate(&result)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn child_under(
|
||||
mut id: Id,
|
||||
parent: Option<Id>,
|
||||
parents: &BTreeMap<Id, Option<Id>>,
|
||||
work: &mut usize,
|
||||
) -> Result<Option<Id>, ModelError> {
|
||||
for _ in 0..=parents.len() {
|
||||
spend(work)?;
|
||||
let Some(actual) = parents.get(&id) else {
|
||||
return Ok(None);
|
||||
};
|
||||
if *actual == parent {
|
||||
return Ok(Some(id));
|
||||
}
|
||||
let Some(next) = actual else { return Ok(None) };
|
||||
id = *next;
|
||||
}
|
||||
Err(ModelError("Layered probe containment cycle.".into()))
|
||||
}
|
||||
|
||||
fn ranks(
|
||||
ids: &[Id],
|
||||
arcs: &BTreeSet<(Id, Id)>,
|
||||
work: &mut usize,
|
||||
) -> Result<BTreeMap<Id, usize>, ModelError> {
|
||||
let mut remaining: BTreeSet<_> = ids.iter().copied().collect();
|
||||
let mut ranks: BTreeMap<_, usize> = BTreeMap::new();
|
||||
while !remaining.is_empty() {
|
||||
let mut ready = None;
|
||||
for id in ids.iter().filter(|id| remaining.contains(*id)) {
|
||||
let mut blocked = false;
|
||||
for (a, b) in arcs {
|
||||
spend(work)?;
|
||||
blocked |= b == id && remaining.contains(a);
|
||||
}
|
||||
if !blocked {
|
||||
ready = Some(*id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Explicit cycle fallback: break the first canonical remaining vertex's
|
||||
// incoming ranking constraints. Actual relation direction is unchanged.
|
||||
let id = ready.unwrap_or_else(|| *ids.iter().find(|id| remaining.contains(*id)).unwrap());
|
||||
let mut rank = 0;
|
||||
for (a, b) in arcs {
|
||||
spend(work)?;
|
||||
if *b == id
|
||||
&& let Some(previous) = ranks.get(a)
|
||||
{
|
||||
rank = rank.max(previous + 1);
|
||||
}
|
||||
}
|
||||
ranks.insert(id, rank);
|
||||
remaining.remove(&id);
|
||||
}
|
||||
Ok(ranks)
|
||||
}
|
||||
|
||||
type Groups = BTreeMap<Option<Id>, Vec<Vec<Id>>>;
|
||||
|
||||
fn measure(
|
||||
parent: Option<Id>,
|
||||
groups: &Groups,
|
||||
headers: &BTreeMap<Id, f32>,
|
||||
sizes: &mut BTreeMap<Id, Size>,
|
||||
gx: f32,
|
||||
gy: f32,
|
||||
work: &mut usize,
|
||||
) -> Result<Size, ModelError> {
|
||||
let Some(layers) = groups.get(&parent) else {
|
||||
return Ok(Size {
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
});
|
||||
};
|
||||
let mut width = 0.0;
|
||||
let mut height = 0.0_f32;
|
||||
for (i, layer) in layers.iter().enumerate() {
|
||||
let mut lw = 0.0_f32;
|
||||
let mut lh = 0.0;
|
||||
for (j, id) in layer.iter().enumerate() {
|
||||
spend(work)?;
|
||||
let content = measure(Some(*id), groups, headers, sizes, gx, gy, work)?;
|
||||
let size = sizes.get_mut(id).unwrap();
|
||||
if groups.contains_key(&Some(*id)) {
|
||||
size.width = size.width.max(content.width + 48.0);
|
||||
size.height = size.height.max(content.height + headers[id] + 24.0);
|
||||
}
|
||||
lw = lw.max(size.width);
|
||||
lh += size.height + if j == 0 { 0.0 } else { gy };
|
||||
}
|
||||
width += lw + if i == 0 { 0.0 } else { gx };
|
||||
height = height.max(lh);
|
||||
}
|
||||
Ok(Size { width, height })
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn place(
|
||||
parent: Option<Id>,
|
||||
origin: Position,
|
||||
groups: &Groups,
|
||||
headers: &BTreeMap<Id, f32>,
|
||||
sizes: &BTreeMap<Id, Size>,
|
||||
positions: &mut BTreeMap<Id, Position>,
|
||||
gx: f32,
|
||||
gy: f32,
|
||||
work: &mut usize,
|
||||
) -> Result<(), ModelError> {
|
||||
let Some(layers) = groups.get(&parent) else {
|
||||
return Ok(());
|
||||
};
|
||||
let mut x = origin.x;
|
||||
for layer in layers {
|
||||
let mut y = origin.y;
|
||||
let mut width = 0.0_f32;
|
||||
for id in layer {
|
||||
spend(work)?;
|
||||
positions.insert(*id, Position { x, y });
|
||||
place(
|
||||
Some(*id),
|
||||
Position {
|
||||
x: x + 24.0,
|
||||
y: y + headers[id],
|
||||
},
|
||||
groups,
|
||||
headers,
|
||||
sizes,
|
||||
positions,
|
||||
gx,
|
||||
gy,
|
||||
work,
|
||||
)?;
|
||||
y += sizes[id].height + gy;
|
||||
width = width.max(sizes[id].width);
|
||||
}
|
||||
x += width + gx;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,881 +0,0 @@
|
||||
//! Experimental geometry evidence, not a native selection or usability oracle.
|
||||
//! See harness/experiments/diagram-readability-20260929/README.md.
|
||||
use oa_core::{Diagram, Id, Position, Project, persistence, projection, routing, validation};
|
||||
use serde_json::{Value, json};
|
||||
use std::{
|
||||
error::Error,
|
||||
fs::{self, OpenOptions},
|
||||
io::Write,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn Error>>;
|
||||
const MIXED: &[u8] = include_bytes!(
|
||||
"../../../harness/experiments/diagram-readability-20260929/mixed-dispatch-original.json"
|
||||
);
|
||||
const WARNINGS: &[u8] = include_bytes!(
|
||||
"../../../harness/experiments/diagram-readability-20260929/mixed-dispatch-expected-diagnostics.json"
|
||||
);
|
||||
const RELEASE: &[u8] = include_bytes!("../../../examples/release1/model.json");
|
||||
const RELEASE_WARNINGS: &[u8] =
|
||||
include_bytes!("../../../examples/release1/expected-diagnostics.json");
|
||||
const EIGHT_VIEW: &[u8] = include_bytes!(
|
||||
"../../../harness/experiments/diagram-readability-20260929/eight-card-view.json"
|
||||
);
|
||||
const MAIN: &str = "00000000-0000-0000-0000-0000000186a1";
|
||||
const EIGHT: &str = "00000000-0038-4000-8000-000000000001";
|
||||
|
||||
fn canonical_diagnostics(value: Value) -> Result<Vec<String>> {
|
||||
let mut rows = value
|
||||
.as_array()
|
||||
.ok_or("Expected a diagnostics array")?
|
||||
.iter()
|
||||
.map(serde_json::to_string)
|
||||
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||
rows.sort();
|
||||
Ok(rows)
|
||||
}
|
||||
|
||||
fn admit(bytes: &[u8], baseline: &[u8]) -> Result<Project> {
|
||||
let project = persistence::decode(bytes)?;
|
||||
let issues = validation::validate(&project);
|
||||
if issues
|
||||
.iter()
|
||||
.any(|i| i.severity == validation::Severity::Error)
|
||||
{
|
||||
return Err(format!("Invalid project: {}", serde_json::to_string(&issues)?).into());
|
||||
}
|
||||
if canonical_diagnostics(serde_json::to_value(&issues)?)?
|
||||
!= canonical_diagnostics(serde_json::from_slice(baseline)?)?
|
||||
{
|
||||
return Err(format!(
|
||||
"Unexpected diagnostics; review without automatically accepting: {}",
|
||||
serde_json::to_string(&issues)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(project)
|
||||
}
|
||||
|
||||
fn representative() -> Result<Project> {
|
||||
let mut project = admit(RELEASE, RELEASE_WARNINGS)?;
|
||||
let view: Diagram = serde_json::from_slice(EIGHT_VIEW)?;
|
||||
if project.diagrams.insert(view.id, view).is_some() {
|
||||
return Err("Representative view ID collision".into());
|
||||
}
|
||||
admit(&serde_json::to_vec(&project)?, RELEASE_WARNINGS)
|
||||
}
|
||||
|
||||
fn rect(point: Position, origin: Position, size: oa_core::Size) -> bool {
|
||||
point.x >= origin.x
|
||||
&& point.x <= origin.x + size.width
|
||||
&& point.y >= origin.y
|
||||
&& point.y <= origin.y + size.height
|
||||
}
|
||||
|
||||
fn distance(point: 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 {
|
||||
(((point.x - a.x) * dx + (point.y - a.y) * dy) / length).clamp(0., 1.)
|
||||
};
|
||||
(point.x - a.x - t * dx).hypot(point.y - a.y - t * dy)
|
||||
}
|
||||
|
||||
// Intentionally returns every distinct candidate, with no selected-edge bias,
|
||||
// UUID winner, click dispatch, viewport clipping, or gesture simulation.
|
||||
fn candidates(
|
||||
project: &Project,
|
||||
view: &projection::ProjectedView,
|
||||
routed: &routing::RoutedView,
|
||||
point: Position,
|
||||
zoom: f32,
|
||||
) -> Value {
|
||||
let edges: Vec<_> = routed
|
||||
.edges
|
||||
.values()
|
||||
.filter_map(|edge| {
|
||||
let segments: Vec<_> = edge
|
||||
.points
|
||||
.windows(2)
|
||||
.enumerate()
|
||||
.filter_map(|(i, pair)| {
|
||||
let d = distance(point, pair[0], pair[1]);
|
||||
(d <= 7. / zoom).then(|| json!({"index":i,"distance":d}))
|
||||
})
|
||||
.collect();
|
||||
(!segments.is_empty()).then(|| json!({"edge":edge.id,"segments":segments}))
|
||||
})
|
||||
.collect();
|
||||
let nodes: Vec<_> = view
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|n| rect(point, n.position, n.size))
|
||||
.map(|n| n.id)
|
||||
.collect();
|
||||
let labels: Vec<_> = routed
|
||||
.edges
|
||||
.values()
|
||||
.filter(|e| {
|
||||
!e.label.text.is_empty() && rect(point, e.label.bounds.position, e.label.bounds.size)
|
||||
})
|
||||
.map(|e| e.id)
|
||||
.collect();
|
||||
let association_labels: Vec<_> = routed
|
||||
.edges
|
||||
.values()
|
||||
.flat_map(|e| {
|
||||
project
|
||||
.relations
|
||||
.get(&e.id)
|
||||
.into_iter()
|
||||
.flat_map(move |relation| {
|
||||
routing::association_end_geometry(relation, e)
|
||||
.into_iter()
|
||||
.filter(move |end| {
|
||||
rect(point, end.label.bounds.position, end.label.bounds.size)
|
||||
})
|
||||
.map(move |end| json!({"edge":e.id,"source_end":end.source_end}))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let radius = (10. / zoom).max(10.);
|
||||
let ports: Vec<_> = view
|
||||
.ports
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
(p.position.x - point.x).abs() <= radius && (p.position.y - point.y).abs() <= radius
|
||||
})
|
||||
.map(|p| json!({"element":p.element,"owner":p.owner}))
|
||||
.collect();
|
||||
json!({"world_point":point,"zoom":zoom,"edge_candidates":edges,
|
||||
"node_occluders":nodes,"label_occluders":labels,"association_label_occluders":association_labels,"port_occluders":ports})
|
||||
}
|
||||
|
||||
fn unobscured(value: &Value) -> bool {
|
||||
[
|
||||
"node_occluders",
|
||||
"label_occluders",
|
||||
"association_label_occluders",
|
||||
"port_occluders",
|
||||
]
|
||||
.iter()
|
||||
.all(|key| value[key].as_array().is_some_and(Vec::is_empty))
|
||||
}
|
||||
|
||||
fn snapshot(project: &Project, diagram: Id, point: Position, zoom: f32) -> Result<Value> {
|
||||
if !zoom.is_finite() || zoom <= 0. || !point.x.is_finite() || !point.y.is_finite() {
|
||||
return Err("Point must be finite; zoom must be finite and positive".into());
|
||||
}
|
||||
let original = project.clone();
|
||||
let diagram = project.diagrams.get(&diagram).ok_or("Unknown diagram")?;
|
||||
let view = projection::project_view(project, diagram.id);
|
||||
let routed = routing::route_diagram(project, diagram, &view);
|
||||
let mut inventory = Vec::new();
|
||||
for edge in &view.edges {
|
||||
let (kind, source, target) = if let Some(r) = project.relations.get(&edge.id) {
|
||||
(format!("{:?}", r.kind()), r.source(), r.target())
|
||||
} else if let Some(t) = project.traces.get(&edge.id) {
|
||||
(format!("Trace:{:?}", t.kind), t.oa, t.sa)
|
||||
} else {
|
||||
return Err("Projected edge has no semantic identity".into());
|
||||
};
|
||||
inventory.push(
|
||||
json!({"id":edge.id,"kind":kind,"source":source,"target":target,
|
||||
"source_port":edge.source_port,"target_port":edge.target_port,
|
||||
"projected_source":edge.source,"projected_target":edge.target,"trace":edge.trace}),
|
||||
);
|
||||
}
|
||||
inventory.sort_by_key(|row| row["id"].to_string());
|
||||
let expected: Option<Value> = if diagram.id.to_string() == MAIN {
|
||||
Some(serde_json::from_slice(include_bytes!(
|
||||
"../../../harness/experiments/diagram-readability-20260929/mixed-answer-key.json"
|
||||
))?)
|
||||
} else if diagram.id.to_string() == EIGHT {
|
||||
Some(serde_json::from_slice(include_bytes!(
|
||||
"../../../harness/experiments/diagram-readability-20260929/eight-answer-key.json"
|
||||
))?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if expected
|
||||
.as_ref()
|
||||
.is_some_and(|key| *key != json!(inventory))
|
||||
{
|
||||
return Err(format!(
|
||||
"Projected semantic inventory differs from independently declared answer key: {}",
|
||||
json!(inventory)
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let mut edges = Vec::new();
|
||||
let mut alternate = Vec::new();
|
||||
for edge in routed.edges.values() {
|
||||
let projected = view
|
||||
.edges
|
||||
.iter()
|
||||
.find(|p| p.id == edge.id)
|
||||
.ok_or("Routed edge missing projected identity")?;
|
||||
let semantic = if let Some(relation) = project.relations.get(&edge.id) {
|
||||
json!({"relation":relation,"source_element":project.elements.get(&relation.source()),
|
||||
"target_element":project.elements.get(&relation.target())})
|
||||
} else {
|
||||
json!({"trace":project.traces.get(&edge.id)})
|
||||
};
|
||||
edges.push(
|
||||
json!({"id":edge.id,"projected":projected,"semantic":semantic,
|
||||
"points":edge.points,"label":{"text":edge.label.text,"fraction":edge.label.fraction,
|
||||
"anchor":edge.label.anchor,"center":edge.label.center,
|
||||
"position":edge.label.bounds.position,"size":edge.label.bounds.size},
|
||||
"effective_pins":edge.pins,"pin_fractions":edge.pin_fractions,
|
||||
"authored_route":diagram.routes.iter().find(|r| r.edge == edge.id),
|
||||
"custom_suspended":edge.custom_suspended,
|
||||
"route_warnings":edge.warnings.iter().map(|w| format!("{w:?}")).collect::<Vec<_>>()}),
|
||||
);
|
||||
// A positive sample proves a geometric alternate under this query policy.
|
||||
// Failure to find one does NOT prove global inaccessibility.
|
||||
let mut line_witness = None;
|
||||
for pair in edge.points.windows(2) {
|
||||
for t in [0.25, 0.5, 0.75] {
|
||||
let p = Position {
|
||||
x: pair[0].x + (pair[1].x - pair[0].x) * t,
|
||||
y: pair[0].y + (pair[1].y - pair[0].y) * t,
|
||||
};
|
||||
let hits = candidates(project, &view, &routed, p, zoom);
|
||||
if unobscured(&hits)
|
||||
&& hits["edge_candidates"]
|
||||
.as_array()
|
||||
.is_some_and(|a| a.len() == 1)
|
||||
{
|
||||
line_witness = Some(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if line_witness.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let label_hits = candidates(project, &view, &routed, edge.label.center, zoom);
|
||||
let label_witness = !edge.label.text.is_empty()
|
||||
&& label_hits["node_occluders"]
|
||||
.as_array()
|
||||
.is_some_and(Vec::is_empty)
|
||||
&& label_hits["port_occluders"]
|
||||
.as_array()
|
||||
.is_some_and(Vec::is_empty)
|
||||
&& label_hits["association_label_occluders"]
|
||||
.as_array()
|
||||
.is_some_and(Vec::is_empty)
|
||||
&& label_hits["label_occluders"]
|
||||
.as_array()
|
||||
.is_some_and(|a| a.len() == 1);
|
||||
alternate.push(json!({"edge":edge.id,"unoccluded_unique_segment_sample":line_witness,
|
||||
"unoccluded_unique_label_center":label_witness.then_some(edge.label.center),
|
||||
"negative_result":"No sampled witness is not proof of global inaccessibility",
|
||||
"native_access":"Not evaluated; Inspector, viewport, selected handles and gesture state excluded"}));
|
||||
}
|
||||
if *project != original {
|
||||
return Err("Projection/routing changed the Project".into());
|
||||
}
|
||||
let query = candidates(project, &view, &routed, point, zoom);
|
||||
let historical_point = Position { x: 1982., y: 375. };
|
||||
let historical_query = candidates(project, &view, &routed, historical_point, 1.);
|
||||
let historical_ids = [
|
||||
"00000000-0000-0000-0000-00000001adb8",
|
||||
"00000000-0000-0000-0000-00000001adb9",
|
||||
];
|
||||
let historical_reproduced = diagram.id.to_string() == MAIN
|
||||
&& unobscured(&historical_query)
|
||||
&& historical_query["edge_candidates"]
|
||||
.as_array()
|
||||
.is_some_and(|rows| {
|
||||
rows.len() == 2
|
||||
&& historical_ids.iter().all(|id| {
|
||||
rows.iter().any(|r| {
|
||||
r["edge"] == *id
|
||||
&& r["segments"]
|
||||
.as_array()
|
||||
.is_some_and(|s| s.iter().any(|s| s["distance"] == 0.))
|
||||
})
|
||||
})
|
||||
})
|
||||
&& historical_ids.iter().all(|id| {
|
||||
routed
|
||||
.edges
|
||||
.get(&id.parse::<Id>().unwrap())
|
||||
.is_some_and(|e| {
|
||||
e.points.windows(2).any(|p| {
|
||||
p[0].x == 1982.
|
||||
&& p[1].x == 1982.
|
||||
&& p[0].y.min(p[1].y) <= 336.
|
||||
&& p[0].y.max(p[1].y) >= 414.
|
||||
})
|
||||
})
|
||||
});
|
||||
Ok(
|
||||
json!({"experiment":"issue38 geometry probe; not feature acceptance",
|
||||
"experiment_declared_base":"715036e132677dd2bc2fb37ed316d93dc9987aec",
|
||||
"build_provenance":"Require external manifest/source hash verification; this field does not identify the executable build",
|
||||
"diagram":diagram.id,"project":project,
|
||||
"project_conserved":true,"projected_view":view,"routed_edges":edges,
|
||||
"bounds":{"position":routed.bounds.position,"size":routed.bounds.size},
|
||||
"query":query,"alternate_access_samples":alternate,
|
||||
"projected_semantic_inventory":inventory,"declared_answer_key":expected,
|
||||
"historical_witness_reproduced":if diagram.id.to_string()==MAIN {Some(historical_reproduced)} else {None},
|
||||
"historical_witness_policy":"Exact IDs, zero distance at (1982,375), no occluders, common x1982 span336..414 beyond shared port lead; zoom1. False is a result, not failure.",
|
||||
"diagnostics":validation::validate(project)}),
|
||||
)
|
||||
}
|
||||
|
||||
// Bounded reconstruction of routing.rs Rect predicates, not a production API.
|
||||
// The clearance calculation additionally requires exactly orthogonal segments.
|
||||
#[derive(Clone, Copy)]
|
||||
struct LabelProbeRect {
|
||||
left: f32,
|
||||
top: f32,
|
||||
right: f32,
|
||||
bottom: f32,
|
||||
}
|
||||
|
||||
impl LabelProbeRect {
|
||||
fn new(position: Position, size: oa_core::Size) -> Self {
|
||||
Self {
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
right: position.x + size.width,
|
||||
bottom: position.y + size.height,
|
||||
}
|
||||
}
|
||||
|
||||
fn inflate(self, amount: f32) -> Self {
|
||||
Self {
|
||||
left: self.left - amount,
|
||||
top: self.top - amount,
|
||||
right: self.right + amount,
|
||||
bottom: self.bottom + amount,
|
||||
}
|
||||
}
|
||||
|
||||
fn overlaps(self, other: Self) -> bool {
|
||||
self.left < other.right
|
||||
&& self.right > other.left
|
||||
&& self.top < other.bottom
|
||||
&& self.bottom > other.top
|
||||
}
|
||||
|
||||
fn crosses(self, a: Position, b: Position) -> bool {
|
||||
// Keep the source's strict bounds and epsilon, including point segments.
|
||||
const EPSILON: f32 = 0.001;
|
||||
if a == b {
|
||||
return a.x > self.left + EPSILON
|
||||
&& a.x < self.right - EPSILON
|
||||
&& a.y > self.top + EPSILON
|
||||
&& a.y < self.bottom - EPSILON;
|
||||
}
|
||||
if (a.x - b.x).abs() < EPSILON {
|
||||
a.x > self.left + EPSILON
|
||||
&& a.x < self.right - EPSILON
|
||||
&& a.y.min(b.y) < self.bottom - EPSILON
|
||||
&& a.y.max(b.y) > self.top + EPSILON
|
||||
} else if (a.y - b.y).abs() < EPSILON {
|
||||
a.y > self.top + EPSILON
|
||||
&& a.y < self.bottom - EPSILON
|
||||
&& a.x.min(b.x) < self.right - EPSILON
|
||||
&& a.x.max(b.x) > self.left + EPSILON
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn clearance(self, a: Position, b: Position) -> f32 {
|
||||
let dx = (a.x.min(b.x) - self.right)
|
||||
.max(self.left - a.x.max(b.x))
|
||||
.max(0.);
|
||||
let dy = (a.y.min(b.y) - self.bottom)
|
||||
.max(self.top - a.y.max(b.y))
|
||||
.max(0.);
|
||||
dx.hypot(dy)
|
||||
}
|
||||
}
|
||||
|
||||
fn label_candidates(project: &Project, diagram_id: Id, edge_id: Id) -> Result<Value> {
|
||||
let original = project.clone();
|
||||
let diagram = project.diagrams.get(&diagram_id).ok_or("Unknown diagram")?;
|
||||
let view = projection::project_view(project, diagram.id);
|
||||
if view.nodes.iter().any(|node| node.visual_parent.is_some()) {
|
||||
return Err("Label candidate probe supports only flat projected nodes".into());
|
||||
}
|
||||
let routed = routing::route_diagram(project, diagram, &view);
|
||||
let target = routed.edges.get(&edge_id).ok_or("Unknown routed edge")?;
|
||||
if target.custom_suspended
|
||||
|| diagram
|
||||
.routes
|
||||
.iter()
|
||||
.any(|route| route.edge == edge_id && route.label.is_some())
|
||||
{
|
||||
return Err("Label candidate probe requires an automatic, unsuspended label".into());
|
||||
}
|
||||
if target.label.text.is_empty() || target.points.len() < 2 {
|
||||
return Err("Label candidate probe requires nonempty text and a routed path".into());
|
||||
}
|
||||
for edge in routed.edges.values() {
|
||||
if project
|
||||
.relations
|
||||
.get(&edge.id)
|
||||
.is_some_and(|relation| !routing::association_end_geometry(relation, edge).is_empty())
|
||||
{
|
||||
return Err("Label candidate probe does not support association-end labels".into());
|
||||
}
|
||||
if edge.id < edge_id && !edge.label.text.is_empty() {
|
||||
return Err("Label candidate probe does not support earlier nonempty labels".into());
|
||||
}
|
||||
if edge
|
||||
.points
|
||||
.iter()
|
||||
.any(|p| !p.x.is_finite() || !p.y.is_finite())
|
||||
|| edge
|
||||
.points
|
||||
.windows(2)
|
||||
.any(|p| p[0].x != p[1].x && p[0].y != p[1].y)
|
||||
{
|
||||
return Err("Label candidate probe requires finite, exactly orthogonal paths".into());
|
||||
}
|
||||
}
|
||||
// All projected nodes are flat, so edge_obstacles has no traversable ancestors.
|
||||
let obstacles: Vec<_> = view
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|node| LabelProbeRect::new(node.position, node.size).inflate(12.))
|
||||
.collect();
|
||||
// Match record_segments' exact undirected deduplication. Semantic ownership
|
||||
// is reported separately below and must not be lost by this score dedup.
|
||||
let mut strokes: Vec<(Position, Position)> = Vec::new();
|
||||
for edge in routed.edges.values() {
|
||||
for pair in edge.points.windows(2) {
|
||||
let (a, b) = (pair[0], pair[1]);
|
||||
if a != b
|
||||
&& !strokes
|
||||
.iter()
|
||||
.any(|&(x, y)| (x == a && y == b) || (x == b && y == a))
|
||||
{
|
||||
strokes.push((a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
let size = oa_core::Size {
|
||||
width: target.label.text.chars().count() as f32 * 7. + 16.,
|
||||
height: 24.,
|
||||
};
|
||||
if size != target.label.bounds.size {
|
||||
return Err(
|
||||
"Production label dimensions differ from this experiment's reconstruction".into(),
|
||||
);
|
||||
}
|
||||
let length = |a: Position, b: Position| (b.x - a.x).hypot(b.y - a.y);
|
||||
let total: f32 = target.points.windows(2).map(|p| length(p[0], p[1])).sum();
|
||||
let mut alternatives = vec![0.5_f32];
|
||||
if total > 0. {
|
||||
let mut traversed = 0.;
|
||||
for pair in target.points.windows(2) {
|
||||
let len = length(pair[0], pair[1]);
|
||||
alternatives.push((traversed + len / 2.) / total);
|
||||
traversed += len;
|
||||
}
|
||||
alternatives.extend((1..20).map(|i| i as f32 / 20.));
|
||||
}
|
||||
alternatives.sort_by(|a, b| {
|
||||
(a - 0.5)
|
||||
.abs()
|
||||
.total_cmp(&(b - 0.5).abs())
|
||||
.then_with(|| a.total_cmp(b))
|
||||
});
|
||||
alternatives.dedup();
|
||||
alternatives.truncate(32);
|
||||
let offsets = [
|
||||
Position { x: 0., y: -18. },
|
||||
Position { x: 0., y: 18. },
|
||||
Position { x: 0., y: -46. },
|
||||
Position { x: 0., y: 46. },
|
||||
Position { x: 0., y: -74. },
|
||||
Position { x: 0., y: 74. },
|
||||
Position {
|
||||
x: size.width / 2. + 18.,
|
||||
y: 0.,
|
||||
},
|
||||
Position {
|
||||
x: -size.width / 2. - 18.,
|
||||
y: 0.,
|
||||
},
|
||||
];
|
||||
let mut rows = Vec::new();
|
||||
let mut scores = Vec::new();
|
||||
for offset in offsets {
|
||||
for &fraction in &alternatives {
|
||||
let anchor = routing::point_along_polyline(&target.points, fraction)
|
||||
.ok_or("Missing candidate anchor")?;
|
||||
let center = Position {
|
||||
x: anchor.x + offset.x,
|
||||
y: anchor.y + offset.y,
|
||||
};
|
||||
let position = Position {
|
||||
x: center.x - size.width / 2.,
|
||||
y: center.y - size.height / 2.,
|
||||
};
|
||||
let bounds = LabelProbeRect::new(position, size);
|
||||
let inflated = bounds.inflate(3.);
|
||||
let score = (
|
||||
obstacles
|
||||
.iter()
|
||||
.filter(|obstacle| obstacle.overlaps(bounds))
|
||||
.count(),
|
||||
0_usize,
|
||||
strokes
|
||||
.iter()
|
||||
.filter(|&&(a, b)| inflated.crosses(a, b))
|
||||
.count(),
|
||||
);
|
||||
let mut own_clearance: Option<f32> = None;
|
||||
let mut foreign_clearance: Option<f32> = None;
|
||||
let mut own_intersections = Vec::new();
|
||||
let mut foreign_intersections = Vec::new();
|
||||
for edge in routed.edges.values() {
|
||||
let mut indices = Vec::new();
|
||||
for (index, pair) in edge.points.windows(2).enumerate() {
|
||||
if pair[0] == pair[1] {
|
||||
continue;
|
||||
}
|
||||
let clearance = bounds.clearance(pair[0], pair[1]);
|
||||
let nearest = if edge.id == edge_id {
|
||||
&mut own_clearance
|
||||
} else {
|
||||
&mut foreign_clearance
|
||||
};
|
||||
*nearest = Some(nearest.map_or(clearance, |old| old.min(clearance)));
|
||||
if inflated.crosses(pair[0], pair[1]) {
|
||||
indices.push(index);
|
||||
}
|
||||
}
|
||||
if !indices.is_empty() {
|
||||
let entry = json!({"edge":edge.id,
|
||||
"relation_alias":project.relations.get(&edge.id).map(|r| &r.alias),
|
||||
"segments":indices});
|
||||
if edge.id == edge_id {
|
||||
own_intersections.push(entry);
|
||||
} else {
|
||||
foreign_intersections.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
scores.push(score);
|
||||
rows.push(
|
||||
json!({"fraction":fraction,"offset":offset,"anchor":anchor,"center":center,
|
||||
"bounds":{"position":position,"size":size},"collision_tuple":score,
|
||||
"own_intersections":own_intersections,"foreign_intersections":foreign_intersections,
|
||||
"own_clearance":own_clearance,"foreign_clearance":foreign_clearance}),
|
||||
);
|
||||
}
|
||||
}
|
||||
let best = scores.iter().min().copied().ok_or("No label candidates")?;
|
||||
let best_indices: Vec<_> = scores
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, &score)| (score == best).then_some(index))
|
||||
.collect();
|
||||
if *project != original {
|
||||
return Err("Project changed during label candidate experiment".into());
|
||||
}
|
||||
Ok(
|
||||
json!({"experiment":"issue38 exhaustive f32 label candidate feasibility; not usability acceptance",
|
||||
"scope":"Unbudgeted exhaustive superset of existing candidates. No 8192-comparison budget, early pruning, early exit, or production chooser claim.",
|
||||
"restrictions":"Flat projected nodes, automatic unsuspended nonempty target label, no association-end labels or earlier nonempty labels, finite orthogonal paths.",
|
||||
"geometry_policy":"Source-exact f32 candidate construction and collision predicates: nodes inflated 12; label inflated 3 for stroke intersections; exact undirected stroke deduplication. Clearances use the uninflated label box. Semantic intersection lists retain every distinct edge owner; counts are not the deduplicated collision score.",
|
||||
"build_provenance":"Require external source/build identity; this field does not identify the executable",
|
||||
"diagram":diagram.id,"edge":edge_id,"text":target.label.text,
|
||||
"project":project,"project_conserved":true,"diagnostics":validation::validate(project),
|
||||
"fraction_count":alternatives.len(),"offset_count":offsets.len(),"candidate_count":rows.len(),
|
||||
"distinct_stroke_count":strokes.len(),
|
||||
"zero_node_zero_stroke_count":scores.iter().filter(|score| score.0 == 0 && score.2 == 0).count(),
|
||||
"best_collision_tuple":best,"best_candidate_indices":best_indices,"candidates":rows}),
|
||||
)
|
||||
}
|
||||
|
||||
fn write_new(path: &Path, bytes: &[u8]) -> Result<()> {
|
||||
let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;
|
||||
file.write_all(bytes)?;
|
||||
file.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
if args.len() == 2 && args[0] == "generate" {
|
||||
// Refuse an existing directory so no previous experiment output is replaced.
|
||||
let out = Path::new(&args[1]);
|
||||
let mixed = admit(MIXED, WARNINGS)?;
|
||||
let eight = representative()?;
|
||||
let scenes = [
|
||||
(
|
||||
"mixed-dispatch",
|
||||
mixed,
|
||||
MAIN,
|
||||
Position { x: 1982., y: 375. },
|
||||
),
|
||||
(
|
||||
"eight-card-representative",
|
||||
eight,
|
||||
EIGHT,
|
||||
Position { x: 600., y: 450. },
|
||||
),
|
||||
];
|
||||
let mut outputs = Vec::new();
|
||||
for (name, project, id, point) in scenes {
|
||||
outputs.push((format!("{name}.json"), serde_json::to_vec_pretty(&project)?));
|
||||
outputs.push((
|
||||
format!("{name}-geometry.json"),
|
||||
serde_json::to_vec_pretty(&snapshot(&project, id.parse()?, point, 1.)?)?,
|
||||
));
|
||||
}
|
||||
fs::create_dir(out)?;
|
||||
write_new(&out.join("mixed-dispatch-original.json"), MIXED)?;
|
||||
write_new(&out.join("release1-original.json"), RELEASE)?;
|
||||
for (name, bytes) in outputs {
|
||||
write_new(&out.join(name), &bytes)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if args.len() == 6 && args[0] == "label-candidates" {
|
||||
let input = fs::read(&args[1])?;
|
||||
let project = admit(&input, &fs::read(&args[2])?)?;
|
||||
let mut result = label_candidates(&project, args[3].parse()?, args[4].parse()?)?;
|
||||
result["original_input_utf8"] = json!(std::str::from_utf8(&input)?);
|
||||
if fs::read(&args[1])? != input {
|
||||
return Err("Input changed during label candidate experiment".into());
|
||||
}
|
||||
result["input_bytes_conserved"] = json!(true);
|
||||
return write_new(Path::new(&args[5]), &serde_json::to_vec_pretty(&result)?);
|
||||
}
|
||||
if args.len() != 8 || args[0] != "probe" {
|
||||
return Err("Usage: generate NEW_DIRECTORY | probe INPUT_JSON_OR_SINGLE_SOURCE EXPECTED_DIAGNOSTICS DIAGRAM_UUID WORLD_X WORLD_Y ZOOM NEW_OUTPUT_JSON | label-candidates INPUT EXPECTED_DIAGNOSTICS DIAGRAM_UUID EDGE_UUID NEW_OUTPUT_JSON".into());
|
||||
}
|
||||
let input = fs::read(&args[1])?;
|
||||
let project = admit(&input, &fs::read(&args[2])?)?;
|
||||
let mut result = snapshot(
|
||||
&project,
|
||||
args[3].parse()?,
|
||||
Position {
|
||||
x: args[4].parse()?,
|
||||
y: args[5].parse()?,
|
||||
},
|
||||
args[6].parse()?,
|
||||
)?;
|
||||
result["original_input_utf8"] = json!(std::str::from_utf8(&input)?);
|
||||
if fs::read(&args[1])? != input {
|
||||
return Err("Input changed during experiment".into());
|
||||
}
|
||||
write_new(Path::new(&args[7]), &serde_json::to_vec_pretty(&result)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn conversation_existing_candidates_cannot_avoid_foreign_allocation() {
|
||||
let project = representative().unwrap();
|
||||
let original = project.clone();
|
||||
let target: Id = "63009b5f-539e-5914-b630-ec6b7fefb4d5".parse().unwrap();
|
||||
let foreign = "725f2e1b-aa2c-5615-9b1f-28da178168fa";
|
||||
let result = label_candidates(&project, EIGHT.parse().unwrap(), target).unwrap();
|
||||
assert_eq!(project, original);
|
||||
assert_eq!(result["project"], serde_json::to_value(&original).unwrap());
|
||||
assert_eq!(result["fraction_count"], 23);
|
||||
assert_eq!(result["candidate_count"], 184);
|
||||
assert_eq!(result["distinct_stroke_count"], 37);
|
||||
assert_eq!(result["zero_node_zero_stroke_count"], 0);
|
||||
assert_eq!(result["best_collision_tuple"], json!([0, 0, 1]));
|
||||
// Independently declared from the saved baseline geometry and a JS
|
||||
// double-precision reconstruction, not generated by this Rust scorer.
|
||||
// Allow f32 interpolation differences without changing the finding.
|
||||
let expected = [
|
||||
(0.5, 274.5),
|
||||
(0.45, 294.8),
|
||||
(0.55, 254.2),
|
||||
(0.6, 233.9),
|
||||
(0.65, 213.6),
|
||||
(0.6761083743842364, 203.),
|
||||
];
|
||||
let near = |value: &Value, expected: f64| {
|
||||
assert!(
|
||||
(value.as_f64().unwrap() - expected).abs() < 0.0002,
|
||||
"{value} differs from declared {expected}"
|
||||
);
|
||||
};
|
||||
let best = result["best_candidate_indices"].as_array().unwrap();
|
||||
assert_eq!(best.len(), expected.len());
|
||||
for (index, (fraction, y)) in best.iter().zip(expected) {
|
||||
let row = &result["candidates"][index.as_u64().unwrap() as usize];
|
||||
near(&row["fraction"], fraction);
|
||||
near(&row["offset"]["x"], 134.5);
|
||||
near(&row["offset"]["y"], 0.);
|
||||
near(&row["center"]["x"], 1296.5);
|
||||
near(&row["center"]["y"], y);
|
||||
near(&row["own_clearance"], 18.);
|
||||
near(&row["foreign_clearance"], 0.);
|
||||
assert_eq!(row["own_intersections"], json!([]));
|
||||
let intersections = row["foreign_intersections"].as_array().unwrap();
|
||||
assert_eq!(intersections.len(), 1);
|
||||
assert_eq!(intersections[0]["edge"], foreign);
|
||||
assert_eq!(intersections[0]["relation_alias"], "sa_repair_allocation");
|
||||
assert_eq!(intersections[0]["segments"], json!([1]));
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn representative_preserves_every_original_record_and_view() {
|
||||
let baseline = admit(RELEASE, RELEASE_WARNINGS).unwrap();
|
||||
let mut generated = representative().unwrap();
|
||||
let added = generated.diagrams.remove(&EIGHT.parse().unwrap()).unwrap();
|
||||
assert_eq!(added.nodes.len(), 8);
|
||||
assert_eq!(generated, baseline);
|
||||
let project = representative().unwrap();
|
||||
let result = snapshot(
|
||||
&project,
|
||||
EIGHT.parse().unwrap(),
|
||||
Position { x: 600., y: 450. },
|
||||
1.,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
result["projected_semantic_inventory"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.len(),
|
||||
12
|
||||
);
|
||||
assert_eq!(
|
||||
result["projected_semantic_inventory"],
|
||||
result["declared_answer_key"]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn complete_scene_preserves_semantics_sentinel_and_authored_route() {
|
||||
let project = admit(MIXED, WARNINGS).unwrap();
|
||||
let before = project.clone();
|
||||
let id = MAIN.parse().unwrap();
|
||||
let result = snapshot(&project, id, Position { x: 1982., y: 375. }, 1.).unwrap();
|
||||
assert_eq!(project, before);
|
||||
assert_eq!(result["project"], serde_json::to_value(&before).unwrap());
|
||||
assert_eq!(project.diagrams.len(), 2);
|
||||
assert_eq!(
|
||||
result["projected_view"]["nodes"].as_array().unwrap().len(),
|
||||
10
|
||||
);
|
||||
assert_eq!(result["routed_edges"].as_array().unwrap().len(), 14);
|
||||
for edge in result["routed_edges"].as_array().unwrap() {
|
||||
let edge_id: Id = serde_json::from_value(edge["id"].clone()).unwrap();
|
||||
assert_eq!(
|
||||
edge["semantic"]["relation"],
|
||||
serde_json::to_value(&before.relations[&edge_id]).unwrap()
|
||||
);
|
||||
}
|
||||
let route = &before.diagrams[&id].routes[0];
|
||||
assert_eq!(
|
||||
route.edge.to_string(),
|
||||
"00000000-0000-0000-0000-00000001adbd"
|
||||
);
|
||||
assert_eq!(route.waypoints, vec![Position { x: 300., y: -100. }]);
|
||||
assert_eq!(route.label.as_ref().unwrap().fraction, 0.4);
|
||||
assert_eq!(
|
||||
snapshot(&project, id, Position { x: 1982., y: 375. }, 1.).unwrap(),
|
||||
result
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn unexpected_diagnostics_and_invalid_source_fail_closed() {
|
||||
assert!(admit(MIXED, b"[]").is_err());
|
||||
assert!(admit(b"{}", b"[]").is_err());
|
||||
let project = admit(MIXED, WARNINGS).unwrap();
|
||||
assert!(
|
||||
snapshot(
|
||||
&project,
|
||||
MAIN.parse().unwrap(),
|
||||
Position { x: 0., y: 0. },
|
||||
0.
|
||||
)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn square_port_corner_is_occluded_even_outside_ten_unit_circle() {
|
||||
let project = admit(MIXED, WARNINGS).unwrap();
|
||||
let diagram = &project.diagrams[&MAIN.parse().unwrap()];
|
||||
let view = projection::project_view(&project, diagram.id);
|
||||
let routed = routing::route_diagram(&project, diagram, &view);
|
||||
let port = &view.ports[0];
|
||||
let point = Position {
|
||||
x: port.position.x + 9.,
|
||||
y: port.position.y + 9.,
|
||||
};
|
||||
assert!(9_f32.hypot(9.) > 10.);
|
||||
for zoom in [1., 2.] {
|
||||
let hits = candidates(&project, &view, &routed, point, zoom);
|
||||
assert!(hits["port_occluders"].as_array().unwrap().iter()
|
||||
.any(|p| p["element"]==json!(port.element) && p["owner"]==json!(port.owner)));
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn analytical_query_controls_distinguish_edges_segments_and_labels() {
|
||||
// Synthetic geometry controls using genuine identities, NOT witness evidence.
|
||||
let project = admit(MIXED, WARNINGS).unwrap();
|
||||
let diagram = &project.diagrams[&MAIN.parse().unwrap()];
|
||||
let mut view = projection::project_view(&project, diagram.id);
|
||||
let mut routed = routing::route_diagram(&project, diagram, &view);
|
||||
view.nodes.clear();
|
||||
view.ports.clear();
|
||||
let first: Id = "00000000-0000-0000-0000-00000001adb8".parse().unwrap();
|
||||
let second: Id = "00000000-0000-0000-0000-00000001adb9".parse().unwrap();
|
||||
routed.edges.retain(|id, _| *id == first || *id == second);
|
||||
for (id, edge) in &mut routed.edges {
|
||||
edge.points = if *id == first {
|
||||
vec![
|
||||
Position { x: -20., y: 0. },
|
||||
Position { x: 0., y: 0. },
|
||||
Position { x: 0., y: 20. },
|
||||
]
|
||||
} else {
|
||||
vec![Position { x: -20., y: 50. }, Position { x: 20., y: 50. }]
|
||||
};
|
||||
edge.label.text.clear();
|
||||
}
|
||||
let point = Position { x: 0., y: 0. };
|
||||
let hits = candidates(&project, &view, &routed, point, 1.);
|
||||
assert_eq!(hits["edge_candidates"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(
|
||||
hits["edge_candidates"][0]["segments"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
assert!(unobscured(&hits));
|
||||
let edge = routed.edges.get_mut(&second).unwrap();
|
||||
edge.points = vec![Position { x: -20., y: 0. }, Position { x: 20., y: 0. }];
|
||||
edge.label.bounds = routing::RoutingBounds {
|
||||
position: Position { x: -5., y: -5. },
|
||||
size: oa_core::Size {
|
||||
width: 10.,
|
||||
height: 10.,
|
||||
},
|
||||
};
|
||||
edge.label.text = "Control label".into();
|
||||
let hits = candidates(&project, &view, &routed, point, 1.);
|
||||
assert_eq!(hits["edge_candidates"].as_array().unwrap().len(), 2);
|
||||
assert_eq!(hits["label_occluders"], json!([second]));
|
||||
assert!(!unobscured(&hits));
|
||||
routed.edges.get_mut(&second).unwrap().label.text.clear();
|
||||
let hits = candidates(&project, &view, &routed, point, 1.);
|
||||
assert!(hits["label_occluders"].as_array().unwrap().is_empty());
|
||||
assert!(unobscured(&hits));
|
||||
}
|
||||
}
|
||||
@@ -759,6 +759,64 @@ impl<'a> RoutingSpace<'a> {
|
||||
ys: sorted_coordinates(obstacles.iter().flat_map(|r| [r.top, r.bottom]).collect()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Experimental bounded lanes around settled other-edge segments. Preserve
|
||||
/// every obstacle coordinate; only new lane coordinates count toward the cap.
|
||||
fn with_lanes(&self, start: Position, end: Position, previous: &[Segment]) -> Self {
|
||||
const EXTRA_LIMIT: usize = 64;
|
||||
let add = |base: &[f32], candidates: Vec<f32>, a: f32, b: f32| {
|
||||
let lo = a.min(b);
|
||||
let hi = a.max(b);
|
||||
let midpoint = f64::from(a) / 2.0 + f64::from(b) / 2.0;
|
||||
let mut extra = sorted_coordinates(
|
||||
candidates
|
||||
.into_iter()
|
||||
.filter(|v| {
|
||||
v.is_finite() && base.binary_search_by(|base| base.total_cmp(v)).is_err()
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
let distance = |v: f32| {
|
||||
if v < lo {
|
||||
f64::from(lo) - f64::from(v)
|
||||
} else if v > hi {
|
||||
f64::from(v) - f64::from(hi)
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
};
|
||||
extra.sort_by(|a, b| {
|
||||
distance(*a)
|
||||
.total_cmp(&distance(*b))
|
||||
.then_with(|| {
|
||||
(f64::from(*a) - midpoint)
|
||||
.abs()
|
||||
.total_cmp(&(f64::from(*b) - midpoint).abs())
|
||||
})
|
||||
.then_with(|| a.total_cmp(b))
|
||||
});
|
||||
extra.truncate(EXTRA_LIMIT);
|
||||
sorted_coordinates(base.iter().copied().chain(extra).collect())
|
||||
};
|
||||
let mut xs = Vec::new();
|
||||
let mut ys = Vec::new();
|
||||
for segment in previous {
|
||||
if segment.a == segment.b {
|
||||
continue;
|
||||
}
|
||||
if segment.a.x == segment.b.x {
|
||||
xs.extend([segment.a.x - CLEARANCE, segment.a.x + CLEARANCE]);
|
||||
}
|
||||
if segment.a.y == segment.b.y {
|
||||
ys.extend([segment.a.y - CLEARANCE, segment.a.y + CLEARANCE]);
|
||||
}
|
||||
}
|
||||
Self {
|
||||
obstacles: self.obstacles,
|
||||
xs: add(&self.xs, xs, start.x, end.x),
|
||||
ys: add(&self.ys, ys, start.y, end.y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -846,15 +904,23 @@ fn route_edge(
|
||||
.enumerate()
|
||||
{
|
||||
let incoming = points.iter().rev().find(|&&p| p != start).copied();
|
||||
let path = fast_path(start, end, &space, &occupied, incoming).or_else(|| {
|
||||
if !search {
|
||||
return None;
|
||||
}
|
||||
let (path, hit_limit) =
|
||||
grid_path(start, end, &space, &occupied, incoming, budget);
|
||||
exhausted |= hit_limit;
|
||||
path
|
||||
});
|
||||
// Only the final leg has a known continuation. Intermediate
|
||||
// authored pins must not inherit the target's terminal direction.
|
||||
let outgoing = (index == pins.len()).then_some(b.point);
|
||||
// Both searches see identical lanes. Earlier legs/current
|
||||
// source stubs affect cost as before, but do not generate lanes.
|
||||
let leg_space = space.with_lanes(start, end, previous);
|
||||
let path = fast_path(start, end, &leg_space, &occupied, incoming, outgoing)
|
||||
.or_else(|| {
|
||||
if !search {
|
||||
return None;
|
||||
}
|
||||
let (path, hit_limit) = grid_path(
|
||||
start, end, &leg_space, &occupied, incoming, outgoing, budget,
|
||||
);
|
||||
exhausted |= hit_limit;
|
||||
path
|
||||
});
|
||||
let Some(path) = path else {
|
||||
failed = true;
|
||||
break;
|
||||
@@ -1051,6 +1117,7 @@ fn fast_path(
|
||||
space: &RoutingSpace<'_>,
|
||||
previous: &[Segment],
|
||||
incoming: Option<Position>,
|
||||
outgoing: Option<Position>,
|
||||
) -> Option<Vec<Position>> {
|
||||
let obstacles = space.obstacles;
|
||||
if obstacles
|
||||
@@ -1070,6 +1137,9 @@ fn fast_path(
|
||||
incoming
|
||||
.zip(path.get(1))
|
||||
.map_or(0.0, |(before, &after)| turn_cost(before, start, after))
|
||||
+ outgoing
|
||||
.zip(path.len().checked_sub(2).and_then(|i| path.get(i)))
|
||||
.map_or(0.0, |(after, &before)| turn_cost(before, end, after))
|
||||
};
|
||||
let estimate = |path: &[Position]| base_cost(path) + join(path);
|
||||
candidates.sort_by(|a, b| estimate(a).total_cmp(&estimate(b)));
|
||||
@@ -1141,12 +1211,14 @@ impl Ord for QueueItem {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn grid_path(
|
||||
start: Position,
|
||||
end: Position,
|
||||
space: &RoutingSpace<'_>,
|
||||
previous: &[Segment],
|
||||
incoming: Option<Position>,
|
||||
outgoing: Option<Position>,
|
||||
budget: &mut usize,
|
||||
) -> (Option<Vec<Position>>, bool) {
|
||||
let obstacles = space.obstacles;
|
||||
@@ -1237,6 +1309,10 @@ fn grid_path(
|
||||
let cost = current.cost
|
||||
+ manhattan(a, b)
|
||||
+ before.map_or(0.0, |before| turn_cost(before, a, b))
|
||||
// Charge before queueing the target so competing arrival
|
||||
// directions are compared by their complete terminal cost.
|
||||
+ outgoing.filter(|_| next == last)
|
||||
.map_or(0.0, |after| turn_cost(a, b, after))
|
||||
+ crossing_cost(a, b, previous);
|
||||
if cost >= costs[state] {
|
||||
continue;
|
||||
@@ -1591,3 +1667,237 @@ impl BoundsBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod terminal_join_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn lanes_preserve_base_coordinates_and_bound_unique_extras_deterministically() {
|
||||
let base: Vec<_> = (0..80).map(|i| 10_000.0 + i as f32).collect();
|
||||
let space = RoutingSpace {
|
||||
obstacles: &[],
|
||||
xs: base.clone(),
|
||||
ys: base.clone(),
|
||||
};
|
||||
let mut previous = Vec::new();
|
||||
for i in 0..100 {
|
||||
let coordinate = i as f32 * 40.0;
|
||||
previous.push(Segment {
|
||||
a: pos(coordinate, 0.0),
|
||||
b: pos(coordinate, 100.0),
|
||||
count: 1,
|
||||
});
|
||||
previous.push(Segment {
|
||||
a: pos(0.0, coordinate),
|
||||
b: pos(100.0, coordinate),
|
||||
count: 1,
|
||||
});
|
||||
}
|
||||
let lanes = space.with_lanes(pos(0.0, 0.0), pos(100.0, 100.0), &previous);
|
||||
previous.reverse();
|
||||
previous.extend(previous.clone());
|
||||
let reordered = space.with_lanes(pos(0.0, 0.0), pos(100.0, 100.0), &previous);
|
||||
assert_eq!(lanes.xs, reordered.xs);
|
||||
assert_eq!(lanes.ys, reordered.ys);
|
||||
for coordinates in [&lanes.xs, &lanes.ys] {
|
||||
assert_eq!(coordinates.len(), 80 + 64);
|
||||
assert!(base.iter().all(|v| coordinates.contains(v)));
|
||||
assert!(coordinates.windows(2).all(|v| v[0] < v[1]));
|
||||
assert!(coordinates.contains(&12.0));
|
||||
assert!(coordinates.contains(&92.0));
|
||||
assert!(!coordinates.contains(&3972.0));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lanes_rank_interval_then_midpoint_and_skip_nonfinite_values() {
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let previous: Vec<_> = (0..100)
|
||||
.map(|i| Segment {
|
||||
a: pos(i as f32 * 40.0, 0.0),
|
||||
b: pos(i as f32 * 40.0, 100.0),
|
||||
count: 1,
|
||||
})
|
||||
.chain(std::iter::once(Segment {
|
||||
a: pos(f32::INFINITY, 0.0),
|
||||
b: pos(f32::INFINITY, 100.0),
|
||||
count: 1,
|
||||
}))
|
||||
.collect();
|
||||
let lanes = space.with_lanes(pos(0.0, 0.0), pos(4000.0, 0.0), &previous);
|
||||
assert_eq!(lanes.xs.len(), 64);
|
||||
assert!(lanes.xs.contains(&1988.0));
|
||||
assert!(lanes.xs.contains(&2012.0));
|
||||
assert!(!lanes.xs.contains(&12.0));
|
||||
assert!(lanes.xs.iter().all(|v| v.is_finite()));
|
||||
assert!(lanes.ys.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shared_lane_space_offers_clear_parallel_path_to_fast_and_grid() {
|
||||
let start = pos(0.0, 0.0);
|
||||
let end = pos(200.0, 0.0);
|
||||
let previous = vec![Segment {
|
||||
a: start,
|
||||
b: end,
|
||||
count: 1,
|
||||
}];
|
||||
let base = RoutingSpace::new(&[]);
|
||||
let lanes = base.with_lanes(start, end, &previous);
|
||||
assert_eq!(lanes.ys, vec![-12.0, 12.0]);
|
||||
let fast = fast_path(start, end, &lanes, &previous, None, None).unwrap();
|
||||
assert_eq!(fast.first(), Some(&start));
|
||||
assert_eq!(fast.last(), Some(&end));
|
||||
// Under experimental P=3, direct cost280 loses to length224 + turns48.
|
||||
// No terminal direction is fixed in this private leg-level witness.
|
||||
// Keep the witness valid when parent compares the baseline coefficient.
|
||||
let expected = path_cost(&[start, end], &previous).min(272.0);
|
||||
assert!((path_cost(&fast, &previous) - expected).abs() < EPSILON);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(start, end, &lanes, &previous, None, None, &mut budget);
|
||||
assert!(!exhausted);
|
||||
let grid = grid.unwrap();
|
||||
assert_eq!(grid.first(), Some(&start));
|
||||
assert_eq!(grid.last(), Some(&end));
|
||||
assert!((path_cost(&grid, &previous) - expected).abs() < EPSILON);
|
||||
}
|
||||
|
||||
fn complete_cost(
|
||||
path: &[Position],
|
||||
before: Position,
|
||||
after: Position,
|
||||
occupied: &[Segment],
|
||||
) -> f32 {
|
||||
let mut complete = vec![before];
|
||||
complete.extend_from_slice(path);
|
||||
complete.push(after);
|
||||
path_cost(&complete, occupied)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_join_prefers_equal_bend_witness_without_shared_trunk() {
|
||||
// Four orientations prevent an accidental horizontal/right-only fix.
|
||||
for orientation in 0..4 {
|
||||
let transform = |p: Position| match orientation {
|
||||
0 => p,
|
||||
1 => pos(-p.x, p.y),
|
||||
2 => pos(p.y, p.x),
|
||||
_ => pos(-p.y, -p.x),
|
||||
};
|
||||
let start = transform(pos(0.0, 0.0));
|
||||
let end = transform(pos(46.0, 180.0));
|
||||
let before = transform(pos(-18.0, 0.0));
|
||||
let after = transform(pos(64.0, 180.0));
|
||||
let occupied = vec![Segment {
|
||||
a: start,
|
||||
b: transform(pos(46.0, 0.0)),
|
||||
count: 1,
|
||||
}];
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let witness = vec![start, transform(pos(0.0, 180.0)), end];
|
||||
// Length262 + two turns48 =310. The other complete L path has
|
||||
// the same bends/length but pays46*0.12=5.52 in shared-run cost.
|
||||
assert!((complete_cost(&witness, before, after, &occupied) - 310.0).abs() < EPSILON);
|
||||
let fast = fast_path(start, end, &space, &occupied, Some(before), Some(after)).unwrap();
|
||||
assert_eq!(fast, witness);
|
||||
assert!((complete_cost(&fast, before, after, &occupied) - 310.0).abs() < EPSILON);
|
||||
// Exercise grid directly; public routing's valid fast path would
|
||||
// otherwise hide a target-state ordering regression in grid search.
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
end,
|
||||
&space,
|
||||
&occupied,
|
||||
Some(before),
|
||||
Some(after),
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
let grid = grid.unwrap();
|
||||
assert_eq!(grid, witness);
|
||||
assert!((complete_cost(&grid, before, after, &occupied) - 310.0).abs() < EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unspecified_continuation_keeps_intermediate_leg_choice() {
|
||||
let start = pos(0.0, 0.0);
|
||||
let pin = pos(46.0, 180.0);
|
||||
let before = pos(-18.0, 0.0);
|
||||
let occupied = vec![Segment {
|
||||
a: start,
|
||||
b: pos(46.0, 0.0),
|
||||
count: 1,
|
||||
}];
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let witness = vec![start, pos(46.0, 0.0), pin];
|
||||
let fast = fast_path(start, pin, &space, &occupied, Some(before), None).unwrap();
|
||||
assert_eq!(fast, witness);
|
||||
// An intermediate authored pin has no known outgoing continuation:
|
||||
// length226 + one turn24 + shared5.52 =255.52 for this leg.
|
||||
assert!((path_cost(&fast, &occupied) - 255.52).abs() < EPSILON);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
pin,
|
||||
&space,
|
||||
&occupied,
|
||||
Some(before),
|
||||
None,
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
assert_eq!(grid.unwrap(), witness);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn straight_and_degenerate_terminal_legs_remain_exact() {
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let start = pos(0.0, 0.0);
|
||||
let end = pos(46.0, 0.0);
|
||||
for after in [pos(64.0, 0.0), pos(28.0, 0.0)] {
|
||||
let before = pos(-18.0, 0.0);
|
||||
let fast = fast_path(start, end, &space, &[], Some(before), Some(after)).unwrap();
|
||||
let expected = if after.x > end.x { 82.0 } else { 130.0 };
|
||||
assert!((complete_cost(&fast, before, after, &[]) - expected).abs() < EPSILON);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
end,
|
||||
&space,
|
||||
&[],
|
||||
Some(before),
|
||||
Some(after),
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
assert_eq!(grid.unwrap(), fast);
|
||||
}
|
||||
assert_eq!(
|
||||
fast_path(
|
||||
start,
|
||||
start,
|
||||
&space,
|
||||
&[],
|
||||
Some(pos(-18.0, 0.0)),
|
||||
Some(pos(18.0, 0.0))
|
||||
)
|
||||
.unwrap(),
|
||||
vec![start]
|
||||
);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
start,
|
||||
&space,
|
||||
&[],
|
||||
Some(pos(-18.0, 0.0)),
|
||||
Some(pos(18.0, 0.0)),
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
assert_eq!(grid.unwrap(), vec![start]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# Automatic layout investigation
|
||||
|
||||
Issue [32](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/32)
|
||||
owns scope, ownership, milestones and integration status. This is an experiment
|
||||
record above released `715036e132677dd2bc2fb37ed316d93dc9987aec`, not an accepted
|
||||
replacement layout contract or a completed fix. User-owned requirements remain
|
||||
in `PROJECT_GOAL.md` and the issue.
|
||||
|
||||
The [first executed experiment](experiments/auto-layout-20260925/results-01.md)
|
||||
records nine Windows fixtures at `e7deea70`: hierarchy/label improvements,
|
||||
repeat stability, and two shared-connector regressions. The candidate remains
|
||||
experimental; successful execution is not acceptance of a replacement command.
|
||||
|
||||
The [target-join experiment](experiments/auto-layout-20260925/results-j.md)
|
||||
isolates a routing score correction with fixed Projects/nodes/ports/endpoints.
|
||||
Its 185 regression checks pass, but an original-scene overlap regression and
|
||||
additional bipartite T contacts prevent a general readability acceptance.
|
||||
|
||||
The [completed scoring/lane comparison](experiments/auto-layout-20260925/results-lanes.md)
|
||||
records J/P/PL/L and closes this fixture-tuning experiment. L passes 188 selected
|
||||
checks and strict core Clippy, but residual ambiguity and a runtime cost signal
|
||||
require broader, independently selected evidence before production adoption.
|
||||
|
||||
## Question and existing evidence
|
||||
|
||||
Can explicit Auto-layout produce a readable arrangement that accounts for
|
||||
connections and their labels, including removal of stale bends, while preserving
|
||||
semantic endpoints, containment/allocation, source parity and reversible editing?
|
||||
|
||||
The current `session::layout` sizes the containment forest, sorts roots using
|
||||
directed edges and alias tie breaks, places four roots per row, and translates
|
||||
authored route points only when both actual endpoints move equally. Its authored
|
||||
route preservation is deliberate and tested in `tests/release_routing.rs` and
|
||||
`tests/state_diagrams.rs`; the user's requested automatic bend replacement needs
|
||||
an explicit amendment, not a silently weakened test.
|
||||
|
||||
The [source map](experiments/auto-layout-20260925/source-evaluator-map.md)
|
||||
identifies the actual callers and preserved input/source/API contracts. The
|
||||
[primary-source research](experiments/auto-layout-20260925/research.md) compares
|
||||
Sirius/Capella workflows, ELK and reuse of the existing Rust router. The
|
||||
[candidate critique](experiments/auto-layout-20260925/candidate-critique.md)
|
||||
records unresolved design gaps before any production choice.
|
||||
|
||||
The existing `routing` module already supplies bounded deterministic orthogonal
|
||||
search, node/header obstacles, fixed semantic port endpoints, crossing/shared-run
|
||||
costs and automatic label collision search. Automatic elbows are derived, not
|
||||
persisted. The investigation should reuse this capability unless experiments
|
||||
show a concrete reason to replace it. Process topology rendering is a different
|
||||
path; its reported overlapping routes do not alone prove an Auto-layout defect.
|
||||
|
||||
## Candidate decisions, not yet accepted
|
||||
|
||||
Compare these materially different choices against visible route/label quality,
|
||||
semantic conservation, predictable user control, runtime/dependency cost,
|
||||
determinism, model size and maintainability:
|
||||
|
||||
1. Retain node arrangement and only reset effective visible route/label constraints.
|
||||
This is a useful control, but cannot by itself optimize poor node ordering.
|
||||
2. Use a hierarchy-aware layered node arrangement and the existing router, with
|
||||
label-aware spacing and bounded crossing-reduction sweeps. Explicit Auto-layout
|
||||
can replace effective visible pins/label offsets; ordinary drag keeps its
|
||||
existing preservation rules. This is a candidate, not a chosen implementation.
|
||||
3. Adopt a mature external layout engine, accounting for ports, labels, nested
|
||||
containers, runtime packaging and coordinate conversion. Evidence must justify
|
||||
the integration/dependency cost over reusing the current router.
|
||||
|
||||
Open contract questions include hidden/folded routes, authored attachment and port
|
||||
anchors, undirected and cyclic graphs, nested cross-boundary edges, repeated
|
||||
layout stability, and the observable treatment of exhausted search/poor results.
|
||||
No option may change semantic endpoints, ownership, allocation, expressions,
|
||||
relation kind or source identity to improve a drawing. Other views must remain
|
||||
unchanged, and one Undo on clean input must recover the complete pre-layout
|
||||
project. Existing application behavior applies an unrelated pending property
|
||||
draft first; that separate Apply is not silently folded into Layout's history.
|
||||
|
||||
The initial experiment retains the current command as the baseline and compares
|
||||
reset-only with a layered prototype isolated under `examples/auto_layout_probe`.
|
||||
Neither prototype changes production behavior. Effective reset eligibility must
|
||||
come from the pre-layout projection and actual endpoint identities; merely being
|
||||
drawn does not make a promoted route's dormant metadata eligible. Explicit label
|
||||
reset means both fraction and offset, while semantic text and endpoint/port
|
||||
attachments remain fixed. Production adoption remains conditional on the
|
||||
critic's hierarchy, stability, direction, measurement and global-work checks.
|
||||
|
||||
The first [probe recipe](experiments/auto-layout-20260925/probe-notes.md) covers
|
||||
nine small SA FunctionalDataflow fixtures. Its [independent source review](
|
||||
experiments/auto-layout-20260925/probe-review.md) found no blocker to that finite
|
||||
diagnostic run and lists important evaluator limitations. After that review,
|
||||
the parent inspected the added ten-call prototype stability loop and formatted
|
||||
the examples; the loop reports every differing/error result without a quality
|
||||
pass. No production file was changed. The experiment intentionally does not
|
||||
establish folded/filtered, State, Allocation, source-bundle or native acceptance.
|
||||
|
||||
## Evaluator before implementation
|
||||
|
||||
Use independently specified small graphs and real project views. Separate proper
|
||||
crossings, collinear shared runs, obstacle collisions, label/card collisions,
|
||||
label/label collisions, routing warnings, bends, length and occupied area. A low
|
||||
crossing count alone can hide coincident edges or enormous drawings. Exempt only
|
||||
explicitly documented intentional containment and common endpoint geometry;
|
||||
never discard a failure because it is inconvenient to the proposed algorithm.
|
||||
|
||||
Compare the current command and the reset-only control before choosing a design.
|
||||
Include a chain longer than the current four-column row, diamond/bipartite cases,
|
||||
nested cross-boundary exchanges, stale authored detours/labels, fixed ports,
|
||||
cycles/self-loops and disconnected components. Check deterministic repeat calls,
|
||||
idempotence, model/source round trips and complete Undo/Redo. A probe is evidence
|
||||
about its named fixtures, not universal graph quality or native usability.
|
||||
|
||||
Actual representative Windows workflows, including meaningful window/zoom sizes,
|
||||
selection and saved reopen, follow an implemented candidate. Linux remains
|
||||
excluded by the current user instruction. The separately published State label
|
||||
candidate in issue36 is not silently treated as integrated into this base.
|
||||
@@ -1,49 +0,0 @@
|
||||
# Small-diagram reading and editing
|
||||
|
||||
Experiment contract for [issue 38](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/38), derived from the user's requirement for intuitive graphical modeling with low cognitive load in [PROJECT_GOAL.md](../PROJECT_GOAL.md). This is a bounded investigation, not acceptance of the application or a routing replacement. Live ownership and dependencies remain in the issue.
|
||||
|
||||
## Evidence and uncertainty
|
||||
|
||||
The user's image contains eight cards and crowded connection corridors despite substantial free space. A selected path is already highlighted. Correctly selecting an edge therefore cannot, by itself, establish that the reported usability problem is solved.
|
||||
|
||||
All displayed names occur in the released `examples/release1` teaching project, but its five saved views do not contain that eight-card arrangement. The original projection, layer identities, positions and authored route overrides are unavailable. Any reconstruction must be labeled representative, with its assumptions stated. It must not be called the user's exact model.
|
||||
|
||||
The existing router already penalizes crossings/shared segments and avoids some label collisions. The editor already highlights selected paths/labels and provides route editing. The investigation must compare actual workflows against these existing capabilities, rather than advertise their presence as a new solution.
|
||||
|
||||
An independently audited historical full-scene witness from the published #32 corpus has ten nodes and fourteen real exchanges. Two edges share a run beyond a common port lead, without node, label or port occlusion at the sampled point. Both have distinct labels and unshared segments elsewhere. This establishes an ambiguous target at that point, **not a globally inaccessible relation**. Regeneration and input through the current application remain necessary; recorded geometry and a picking-helper test are insufficient.
|
||||
|
||||
The [probe, fixtures and independent source review](experiments/diagram-readability-20260929/README.md) make those assumptions executable. Review corrected an initial port-hit radius assumption, a five-edge omission from the representative answer key and an incomplete warning baseline. [Current-router execution](experiments/diagram-readability-20260929/run-results.md) passes five tests and reproduces the historical overlap without changing the model. The mixed-layer eight-card view has twelve actual relationships and uses Traceability, which flattens visual parents; it is not evidence for nested/folded controls. Native reading/editing workflows remain a separate gate.
|
||||
|
||||
## Alternatives and decision boundary
|
||||
|
||||
Criteria are correct relationship identity, useful direct editing, readable paths and labels at working scale, preserved authored intent, predictable latency, and maintainable scope.
|
||||
|
||||
| Candidate | Useful outcome | Reason to reject or defer |
|
||||
| --- | --- | --- |
|
||||
| Explicit choice at ambiguous connection hits | Deliberately target an overlapping edge without moving the model | Ordinary clicks become cumbersome; selected-edge bend/label editing is intercepted; it merely prints answers while the diagram remains unreadable |
|
||||
| Local route/label separation | Trace connections without confusing shared runs or detached labels | Authored pins/ports change, unrelated routes regress, occupied area makes Fit unreadable, or expensive rerouting harms interaction |
|
||||
| Existing focused views | Answer a scoped engineering question with fewer unrelated lines | Hides a required relation or substitutes filtering for the ability to edit the complete small view |
|
||||
| Selected-label association cue | Associate a displaced label with its highlighted edge | Adds visual noise, conceals nearby content, or fails to address the demonstrated tracing errors |
|
||||
|
||||
No implementation candidate is accepted yet. First perform a complete-scene identify/select/repair/undo task and a create-connection task. If targetability is already adequate but tracing fails, prioritize association/separation evidence over additional selection machinery. Any narrow improvement leaves the wider readability gate open until measured directly.
|
||||
|
||||
Capella supports local label alignment/reset and a selected edge-to-label attachment cue ([official layout guide](https://github.com/eclipse-capella/capella/blob/master/doc/plugins/org.polarsys.capella.tipsandtricks.doc/html/Tips%20and%20tricks/8_Other%20layout%20facilities/8_Other%20layout%20facilities.mediawiki)). Sirius distinguishes crossing jump marks from label attachment links ([official diagram guide](https://eclipse.dev/sirius/doc/user/diagrams/Diagrams.html)). These provide comparable local repair tools; neither establishes that a chooser or jump mark solves long coincident paths in this application.
|
||||
|
||||
## Evaluator
|
||||
|
||||
Freeze fixture bytes, source/build, semantic IDs and endpoint answer key, projection, authored routes, camera/window size and an untouched sentinel view before the run. Preserve failed attempts. Include disjoint, crossing, coincident/opposed, near-coincident, shared-endpoint, long/identical-label, fixed-port and nested/folded controls. Do not silently simplify a scene until its failure disappears.
|
||||
|
||||
1. **Read:** trace requested relations and identify their endpoints in the complete diagram before showing an answer-bearing Inspector/chooser. Record wrong turns, ambiguous labels/arrowheads, time and recovery actions. Keep this separate from lookup accuracy.
|
||||
2. **Select:** deliberately reach each competing actual relation at the ambiguous location. Check positive controls at its unique label/unshared segment. Ordinary one-target points stay direct. Selection and cancellation preserve model, history, view and layer. Exercise left click, context targeting and group admission independently.
|
||||
3. **Draw:** create an intended valid relationship in the populated scene, then identify and edit the new connection. Check refused endpoints and cancellation with no unintended relation or history transaction.
|
||||
4. **Repair:** move one label, add/move/remove a bend and adjust an eligible attachment. Compare the complete Project against independently declared changes. Semantic endpoints, port ownership, other authored routes and sentinel views remain exact. A gesture commits once; Undo/Redo and save/reopen recover exact authored state.
|
||||
5. **Recover:** Escape, Help, focus departure, view/projection changes and stale queued input must not commit unintended geometry or retain a held gesture. Failed source/model validation preserves the prior state and redo.
|
||||
6. **Measure:** report shared-run length per distinct edge pair, nonincident contacts, crossings, node penetrations, label/node/stroke overlap, label association distance, occupied area, Fit scale and action latency separately. Include screen-space near overlaps; world-coordinate separation alone can remain unreadable. Do not hide regressions in one weighted score.
|
||||
|
||||
The router deliberately freezes other edges during a route preview, then allows automatic paths/labels to settle on commit. Preserve semantic and authored-field equality; record and assess that visual settlement instead of assuming whole-scene preview equality. Evaluate translation and UUID variants so a favorable identity/order does not become the claimed algorithmic result.
|
||||
|
||||
## Implementation boundaries
|
||||
|
||||
Ports, nodes, selected attachments/bends/labels and group selection can intercept input before ordinary edge picking. A helper-only change does not cover the production workflow. Any candidates must deduplicate by semantic edge identity, distinguish semantic endpoints from folded visual endpoints, retain captured document/diagram/revision validation, and remain observational until an explicit model or geometry edit.
|
||||
|
||||
The existing selected-edge tie preference supports direct dragging; do not replace it with unconditional cycling. A transient ambiguity preview must not create a bend or apply a pending property draft. Coordinate contextual selection with #43 and performance with #44. This investigation does not resume the paused #32 planner or absorb the separate #40 allocation-drag and #41 palette contributions.
|
||||
@@ -0,0 +1,38 @@
|
||||
# #32 candidate critique — 2026-09-25
|
||||
|
||||
Read-only adversarial review of `harness/auto-layout-investigation-20260925.md` in the715036e-based isolated checkout, against the source/evaluator map. This critiques candidate choices; no implementation, execution or acceptance is claimed.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Use the existing explicit **Command::Layout / Auto-layout / Arrange elements** operation for the new automatic behavior. The user specifically asks that operation to replace bends and consider labels/intersections. A second command/UI choice would preserve the obsolete behavior as a competing default without demonstrated need. Deliberately amend its documented contract and focused preservation tests, retain exact Undo, and retain existing ordinary drag/Arrange-next-drag contracts. A new command becomes warranted only if concrete compatibility/user workflows require both automatic policies, not merely because a test currently asserts old behavior.
|
||||
|
||||
Prefer comparing candidate1 reset-only against candidate2 layered siblings plus the existing router. No external engine is justified yet. The existing router already creates derived elbows, so reset does not require writing every solver corner as a persisted hard pin. Keep generated corners derived initially; the saved node placement plus remaining explicit attachments determines their repeatable reconstruction.
|
||||
|
||||
Recommended explicit Layout route contract: identify eligible visible, non-promoted edges from the **pre-layout projection**, remove their stored waypoints and label override (fraction and offset together), retain source/target attachments and node port anchors. Retain unrelated/hidden/promoted route records with existing equal-delta endpoint-owner translation. Do not call broad Reset routing if that also clears attachments. Preserve stable route-list order and remove an emptied record only under an explicit canonical no-metadata rule. Layout-generated record churn is not progress.
|
||||
|
||||
## Blocking design gaps before accepting candidate2
|
||||
|
||||
1. **Eligibility must be frozen once.** Visible edges, semantic endpoint-owner placements and promoted endpoints are different sets. Compute the reset set before node movement using projection visibility plus actual owner identity, not “every stored edge” or endpoints merely present in `d.nodes`. A filtered/hidden edge can retain a valid route; a folded edge may be drawn from an ancestor while its own route is suspended. Recomputing eligibility mid-layout risks erasing metadata when visibility/promotion changes. Small experiment: parallel visible/filtered edges, one folded child endpoint, and one both-endpoints-fold-to-same-anchor edge, all with distinctive pins/labels/attachments. Require only declared reset members to change, and retained pins to translate only through the existing owner-delta rule. Unfold/unfilter must reveal the retained custom route.
|
||||
|
||||
2. **Two forests are needed conceptually, not two model hierarchies.** The authored projection-parent forest includes folded descendants; the rendered topology may omit them. Reordering only rendered nodes can leave hidden children outside resized parents or leave future expand geometry broken. Conversely, expanding all hidden content for outer layout wastes space and ignores the actual view. Decide visible sibling arrangement versus hidden subtree placement/reservation explicitly. Lift each rendered inter-subtree edge to the relevant direct children at its lowest common ancestor; do not flatten every edge to roots (loses nested ordering) or count the same edge at every depth as independent demand. Small experiment: nested A/B children with crossed exchanges, folded A, external sibling C and a State entry/exit boundary. Check containment/header/port-footer rules before and after expand, with semantic parents/allocations exact.
|
||||
|
||||
3. **Idempotence will fail if spacing compounds current sizes.** Current measure uses each authored `node.size` as a lower bound. If label clearance expands a container and the next call adds the same margin again, repeated Arrange grows indefinitely. Label spacing based on previous routed bounds can similarly oscillate. Decide whether current sizes are immutable minima, or may shrink; the latter exceeds today's behavior and needs justification. Compute desired padding from content minima with `max`, not repeated addition to an already padded size. Small experiment: ten consecutive calls on nested long-label/parallel-edge fixtures, comparing full Projects after first vs second and sizes after tenth; repeat after Save/reparse. A two-call-only test can miss alternating period-two layouts.
|
||||
|
||||
4. **Cycle/direction policy is not settled by “stable sweeps”.** Some projected edges are undirected; direction may be semantic or merely an endpoint representation. Use directed topology where justified, deterministic SCC treatment for cycles, and explicit undirected ordering inputs. Do not arbitrarily make a Capability/Traceability edge's serialized orientation a mandatory rank. Freeze alias/identity tie rules; crossing sweeps require a stable acceptance tie-break to avoid ping-pong. Small experiment: directed diamond+return, reversed undirected endpoint records, self-loop, parallel/reversed edges and disconnected isolates. Permute input records; independently require identical output for identical IDs and stable quality under UUID changes (not necessarily identical coordinates under reidentification).
|
||||
|
||||
5. **Label reset and label-aware spacing need different evidence.** Clearing authored overrides is a reasonable explicit-auto interpretation but must be announced, since issue32 says “take into account” labels, not explicitly erase them. Retain semantic text/typed references; only the target view's override changes. A stale far-away label is a concrete reset fixture; an intentionally constrained attachment/label case tests whether residual collisions are honestly reported. Base715 label widths are scalar estimates, and State title/multiline geometry is known inaccurate without36. Do not tune spacing to claim accurate measured-State acceptance on715. First isolate ordinary/association labels; use conservative declared bounds for experiments, then rerun State B/W/U once36 integrates. Font-free core/API parity forbids quietly using desktop-only font results inside Command::Layout.
|
||||
|
||||
6. **Bounded sweeps do not alone bound runtime.** Each complete route evaluation invokes previous-edge interactions, node obstacles and label comparisons; repeated per-sibling trial routing can multiply this cost by nodes×sweeps. Lifting topology naively can multiply edges×depth. Define global deterministic work budgets for candidate ordering/scoring, not just a fixed iteration count, and retain the best valid candidate on exhaustion. Route only a bounded number of whole candidates; cheap crossing surrogates can rank candidates but final acceptance must inspect actual geometry. Small experiment: a fixed family increasing sibling count/edge density/nesting, recording candidate count, comparison/work counters and wall time; include no-edge/isolate cases so they do not pay quadratic routing costs. No hard latency threshold should be fabricated from one machine.
|
||||
|
||||
## Input/source/API contract checks
|
||||
|
||||
- Clean whole-view Layout should create one reversible model/source transaction. `app.rs` applies a pending property draft before executing Layout, potentially as a separate transaction; do not accidentally promise one Undo reverses both an unrelated draft Apply and Layout. Use a clean-input one-step Undo oracle and a separate valid/invalid pending-draft admission test. Keep diagram UUID remapping, stale selection handling and disabled/pending form policy.
|
||||
- `prepare_command`/Document/source bundle/REST dry-run must produce the same Project for the same inputs without GUI fonts, caches or selection. A frontend-only rearrangement would fail this. Roundtrip the stored record representation, check unrelated source files/comments remain exact, and recover the exact old source/model with Undo—not merely visually similar positions.
|
||||
- Keep Allocation Arrange-next-drag, ordinary group translation, semantic ports, reconnect, Hide/show, collapse flags and other diagrams unchanged. A route reset belongs only to explicit Layout. A failed candidate must not clear history or leave a partially reset diagram.
|
||||
- Native validation later needs visible controls, Fit/export agreement, actual label containment and route readability, plus Save/reopen/Undo. Do not extend the implementation merely to expose a new State Auto-layout control before a demonstrated workflow need; shared State initialization still needs regression coverage.
|
||||
|
||||
## Smallest discriminating experiment set
|
||||
|
||||
Freeze six hand-built cases before implementation: (A) stale dogleg+far label with fixed attachments, (B) two-container reversed sibling connections with a known zero-crossing witness, (C) nested folded/filtered route-conservation sentinel, (D) cycle/self-loop/parallel/undirected variants, (E) long ordinary/association labels with feasible compact clearance, (F) dense bounded stress. Compare existing Layout, reset-only, and a layered prototype on the same independent vector: invalid overlap/penetration, label collisions, proper crossings, positive collinear overlap, turns, path length/stretch, area and routing warnings. Include ten-call idempotence, exact other-view/semantic conservation, source roundtrip and Undo/Redo.
|
||||
|
||||
Candidate2 earns selection only if it materially improves at least B/E over reset-only without regressing the hard invariants or bounded workload. A tie favors the smaller candidate. A nonplanar or contradictory-fixed-port fixture may retain crossings; zero-crossing-by-overlap, giant detours, hidden edges or clipped labels is not a solution. Failure on a named fixture should revise the exact layer/policy implicated, not trigger an automatic wholesale engine dependency.
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Compare fixed Project/node/port/endpoint geometry and report routing changes.
|
||||
|
||||
Usage: python compare_probe.py OLD_JSONL NEW_JSONL NEW_OUTPUT_JSON
|
||||
No layout-quality pass is inferred from equal inputs or successful execution.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
|
||||
old_path, new_path, out = map(Path, sys.argv[1:])
|
||||
def read(path):
|
||||
rows = [json.loads(line) for line in path.read_text(encoding='utf-8').splitlines()]
|
||||
return {row['fixture']: row for row in rows if 'fixture' in row}
|
||||
old, new = read(old_path), read(new_path)
|
||||
assert old.keys() == new.keys()
|
||||
def variants(row):
|
||||
yield 'before', row['before_project'], row['before']
|
||||
yield 'baseline', row['after_project'], row['after']
|
||||
for name in ['reset_only_control', 'experimental_candidate', 'manual_planar_order_witness']:
|
||||
if row[name] is not None:
|
||||
yield name, row[name]['project'], row[name]['metrics']
|
||||
def endpoints(metrics):
|
||||
return {e['id']: [e['points'][0], e['points'][-1]] for e in metrics['routed_edges']}
|
||||
keys = ['proper_crossings', 'pairwise_collinear_shared_length',
|
||||
'nonterminal_pairwise_shared_length', 'unrelated_node_collisions',
|
||||
'unrelated_edge_node_penetrations', 'label_node_collisions',
|
||||
'label_label_collisions', 'unrelated_label_stroke_intersections',
|
||||
'warning_count', 'route_bends', 'route_length', 'drawing_area']
|
||||
results = []
|
||||
for name in old:
|
||||
lhs, rhs = list(variants(old[name])), list(variants(new[name]))
|
||||
assert len(lhs) == len(rhs)
|
||||
for (variant, op, om), (other, np, nm) in zip(lhs, rhs):
|
||||
assert variant == other
|
||||
fixed = {'project':op == np, 'nodes':om['projected_nodes'] == nm['projected_nodes'],
|
||||
'ports':om['projected_ports'] == nm['projected_ports'],
|
||||
'route_endpoints':endpoints(om) == endpoints(nm)}
|
||||
results.append({'fixture':name, 'variant':variant, 'fixed_geometry':fixed,
|
||||
'metrics':{key:{'old':om[key], 'new':nm[key]} for key in keys},
|
||||
'new_point_contacts':nm.get('point_contacts'),
|
||||
'new_point_contact_details':nm.get('point_contact_details')})
|
||||
summary = {'old_sha256':hashlib.sha256(old_path.read_bytes()).hexdigest(),
|
||||
'new_sha256':hashlib.sha256(new_path.read_bytes()).hexdigest(),
|
||||
'all_projects_nodes_ports_endpoints_exact':all(all(r['fixed_geometry'].values()) for r in results),
|
||||
'scope':'Fixed-geometry comparison; quality vector retained, no aggregate quality pass.',
|
||||
'results':results}
|
||||
with out.open('x',encoding='utf-8') as f:
|
||||
json.dump(summary,f,indent=2)
|
||||
f.write('\n')
|
||||
print(json.dumps({k:v for k,v in summary.items() if k != 'results'}))
|
||||
for row in results:
|
||||
if row['variant'] == 'experimental_candidate':
|
||||
print(json.dumps({'fixture':row['fixture'], 'fixed_geometry':row['fixed_geometry'],
|
||||
'changed_metrics':{k:v for k,v in row['metrics'].items() if v['old'] != v['new']},
|
||||
'point_contacts':row['new_point_contacts']}))
|
||||
@@ -0,0 +1,46 @@
|
||||
# L results and four-way routing experiment audit
|
||||
|
||||
Recommendation: stop tuning these fixtures. L is a useful experimental witness that route alternatives affect sharing, but its small layered benefit and material runtime signal do not presently justify its per-leg preprocessing as a production default. Keep J as the simpler independently motivated scoring correction candidate; decide L only against frozen independent scenes and route-only timing. No production/native acceptance claimed.
|
||||
|
||||
## Verified final L result
|
||||
|
||||
Primary J06 pin `08656b18bf8934cf264469cf68fc6dea97c15cbb`; L11 pin `e8ec6dbb3160f62476a5557f14605f68959f65fe`. Both recorded offline dev/gnullvm probe commands exit0, source unchanged, failure null. Verified receipt log hashes. Separate raw-output traversal confirms all37 Projects, projected nodes/ports and per-edge endpoint records exactly equal. All nine candidate supported/repeat-input/idempotence/ten-call/JSON-and-single-source-roundtrip results remain true, with unchanged conservation and baseline history checks. Candidate Command/Undo integration remains absent.
|
||||
|
||||
J→L changed scalar rows only:
|
||||
|
||||
- Original bipartite raw sharing872→724, nonterminal800→652.
|
||||
- Layered bipartite raw187→176, nonterminal115→104; drawing area175960→165360.
|
||||
- Original two-container raw/nonterminal54→12.
|
||||
- Two-container baseline and reset raw/nonterminal18→12 each.
|
||||
|
||||
The other32 rows are unchanged in recorded scalar quality metrics. No changed point-contact, proper-crossing, length, bend, warning or collision counts in J→L. Independently comparing full candidate metric objects confirms all nine L layered metrics exactly equal PL, not merely the headline totals. Remaining layered bipartite104 nonterminal shared units still prohibit a solved-traceability claim.
|
||||
|
||||
Test10 receipts record135+7+13+18+2+13=188 passed,0 failed/ignored, exit0, unchanged source. J02 and L10 command argv and entire recorded environment dictionaries compare equal. Their routing_geometry test summary elapsed4.30s versus16.43s (~3.82 times, +12.13s); parent reports no concurrent agent compiler. This is a material cost signal, not a controlled routing benchmark: suite runtime includes varied tests and scheduling effects, with no repeated route-only timing. It must not be dismissed by quoting cargo compilation time or presented as an established scaling law.
|
||||
|
||||
Verified37 L schematic image hashes/lengths and manifest input hash. Native/glyph rendering was not exercised. Strict Clippy12 was active when assigned and is outside this audit; no outcome inferred.
|
||||
|
||||
## Four-way conclusion
|
||||
|
||||
All numbers below are raw pairwise shared length; inspect the preceding audits for contacts/area/turn tradeoffs.
|
||||
|
||||
| Scene/variant | J | P | P+L | L |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Layered bipartite |187|187|176|176|
|
||||
| Original bipartite |872|730|724|724|
|
||||
| Baseline/reset bipartite |276|276|72|276|
|
||||
| Original two-container |54|6|12|12|
|
||||
| Baseline/reset two-container |18|18|12|12|
|
||||
|
||||
P has no layered benefit. P+L's baseline bipartite72 means only common terminal sharing remains, but proper crossings rise0→1, length+24 and area+19392; L alone does not produce that tradeoff. The strongest ordinary two-container sharing result is P6, at an extra bend,12 length units and one T contact. Neither the coefficient nor lanes dominates all vectors. J diamond's isolated improvement remains valid but does not erase its original bipartite regression.
|
||||
|
||||
Next scope should be finite and specified before inspecting outcomes: one realistic nested/folded scene, one mixed fan-in/out with a fixed edge-ID permutation, and one modest sparse scene measured by route-only timing and warning/budget counts. Preserve endpoint/model constraints and evaluate traceability, collisions, bends/length/area jointly. Do not silently extend unsupported layered folded behavior into an acceptance claim. Set practical timing and readability criteria before repeating improvement. If L does not show proportionate independent benefit, omit it; avoid adding configuration/architecture solely to retain every experiment. The explicit Layout reset policy and ordinary input/Undo/Save lifecycle are still separate implementation work.
|
||||
|
||||
## Evidence identities
|
||||
|
||||
J06 output `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
|
||||
L11 output `64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d`.
|
||||
L11 result.json `feee84c2fde115c22ea865033ff2d136da2aace1f1c8a7423c8add11358366a8`.
|
||||
L comparison JSON `e1e23e6c2a50cd384457bb061d5b70a740f586f42767164fad9703ecbb4096a8`.
|
||||
L contact audit JSON `6f6cc674c27d3f43001fe1751ef3b09332caa9ddca396759f5525f811cbe1aaf`.
|
||||
|
||||
Read-only audit of completed records; no build/probe/helper rerun, source edit or publication. Earlier independent J/P/PL source/results notes retain grid-axis, subdivision-score, capped retained coordinates versus unbounded preprocessing, stable-edge-order and approximate-label limitations.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Bounded L lane-candidate source review
|
||||
|
||||
Reviewed routing.rs SHA256 `af5995af10c8e3b30c5c6fb776a2ac2678eeef59dd58eb0cdb3d5c62cd153f1b` before parent formatting. Static inspection only; no builds or source edits. No blocking implementation finding for the finite nine-fixture P+L / J+L probe comparison.
|
||||
|
||||
The code retains all sorted base obstacle coordinates and adds at most64 unique extras EACH axis (128 total), filters nonfinite generated values, deduplicates before ranking, then ranks distance from the start/end axis interval, distance from its midpoint, and numeric value. Final lists return to coordinate order. It derives perpendicular offsets only from nondegenerate settled other-edge segments. The current edge's earlier legs/source stub still contribute occupied scoring but do not generate lanes. Fast/grid receive the identical per-leg RoutingSpace; obstacles, endpoints, authored pins, terminal joins and fallback remain unchanged.
|
||||
|
||||
Three new tests cover80 retained base coordinates plus64 extras per axis, previous-segment reorder/duplication invariance, nearest-interval/midpoint selection and nonfinite rejection, and direct calls to fast/grid sharing the same parallel-lane witness. The latter expects min(direct cost,272) and supports both coefficients. No test success is inferred before execution.
|
||||
|
||||
Test-scope caveat sent to parent: the existing `unspecified_continuation_keeps_intermediate_leg_choice` test deliberately hardcodes baseline coefficient0.12, path choice and cost255.52. At P3, the shared penalty caps80 and the alternative is cheaper; a whole private suite at P3 can fail that baseline-policy assertion. Preserve the result honestly; restore0.12 for baseline-suite claims or explicitly distinguish experimental tests. This does not block a diagnostic P+L probe.
|
||||
|
||||
Limits relevant to interpreting results:
|
||||
|
||||
-64 bounds retained coordinates, not scan/sort work. Every endpoint-pair/leg constructs candidates from all previous segments; this preprocessing is outside the search-step budget. No large-scene performance guarantee.
|
||||
- Added coordinates can make the grid exceed65536 cells even when its original grid fit. Existing exhaustion warning/fallback is the evidence to inspect, not something to suppress.
|
||||
- Grid scoring is coordinate-subdivision-sensitive: strict-interior crossing tests can miss contacts at inserted grid vertices, and per-segment capped overlap charges can change with subdivision. Therefore a grid result can change due to scoring partition as well as newly offered parallel lanes. Keep independent contact/shared-interval metrics authoritative for quality observations.
|
||||
- Rank uses one axis and does not filter segment extent on the other; remote lanes can consume the cap. This deterministic heuristic is not proof of optimal lane coverage. The router still uses a feasible fast path before grid, two-axis rather than signed-direction search state, stable sequential edge order, and local hard-pin legs.
|
||||
|
||||
Required experiment interpretation: compare P+L to P and J+L to J with exact Project/node/port/endpoints, all quality metrics and warning counts. Retain label collisions, T/bend contacts, length/turn/area regressions; fewer shared units alone is not acceptance. No broad production or native readability conclusion follows from this finite source review.
|
||||
|
||||
Current formatted routing SHA256: 3a8af7a44f8f32bd9fb94dddd9184fafcf64c93c510025169c62958566bbaedf. Reread formatted lane construction: filtering/ranking/cap semantics agree with reviewed candidate. No mechanical original-byte whitespace comparison claimed. Parent plans exactly the three lane-filtered private tests for P+L, then restores0.12 for the full baseline suite; that appropriately separates the baseline-policy assertion noted above.
|
||||
@@ -0,0 +1,35 @@
|
||||
# P+L results independent audit
|
||||
|
||||
P+L demonstrates that additional lanes can remove one scene's nonterminal overlap, but adds a proper crossing and gives only a small layered improvement. It does not yet justify adopting the extra heuristic as a general production default. Static record audit only; no reruns, builds or source edits.
|
||||
|
||||
Compared P07 `3d7adff923dee5bed54dfdccc119dbee0c7c2773` with PL09 `d0be9ff0674373fcf9623daf62bbf50dad02c4df`. Both probe receipts exit0, failure null, unchanged source; all logged hashes independently checked. Separate raw-output traversal confirms all37 Projects, projected nodes/ports and route endpoint records exact. All nine candidate support/repeat/idempotence/ten-call/roundtrip results remain true; conservation and baseline Command::Layout history checks match P. Candidate Undo integration remains untested.
|
||||
|
||||
Test08 actually ran `cargo test --locked --offline -p oa-core --lib lane`: five passed,130 filtered, zero failed/ignored. This is three new routing lane tests plus two existing scenario-layout tests, not a whole core-suite pass.
|
||||
|
||||
All changed numeric-vector rows, P→PL:
|
||||
|
||||
| Scene/variant | Sharing raw / nonterminal | Other changes |
|
||||
|---|---|---|
|
||||
| bipartite before |730→724 /658→652|contacts10→9; bends5→4; length2076→2064|
|
||||
| bipartite baseline |276→72 /204→0|proper crossings0→1; contacts6→5; length3284→3308; area300576→319968|
|
||||
| bipartite reset |276→72 /204→0|same changes as baseline|
|
||||
| bipartite layered |187→176 /115→104|area175960→165360; contacts9 unchanged|
|
||||
| two-container before |6→12 /6→12|contacts3→2; bends5→4; length1524→1512|
|
||||
| two-container baseline |18→12 /18→12|no other scalar change|
|
||||
| two-container reset |18→12 /18→12|no other scalar change|
|
||||
|
||||
Remaining30 rows unchanged; eight other layered vectors unchanged. No new label-collision or warning-count changes appear. The baseline/reset proper crossing is a real quality tradeoff, not an automatic failure: a visible isolated crossing may be easier to trace than coincident routes. Conversely, zero proper crossings in the layered scene still accompanies104 nonterminal shared units. Two-container original sharing doubles6→12 despite fewer contacts/turns. No single scalar orders all these results.
|
||||
|
||||
Viewed the baseline and layered bipartite PNGs. Baseline channels separate except for the isolated crossing; layered channels retain shared horizontals. Verified all37 offline image hashes/lengths and manifest input binding. These are schematic core geometry, not actual font/native rendering or a user traceability test.
|
||||
|
||||
Performance/complexity: probe command elapsed approximately67.1s(P) and69.7s(PL), but these cargo invocations include compilation; they are not comparable routing benchmarks and establish no overhead bound. The new code scans/sorts all prior segments for each endpoint-pair/leg;64-per-axis limits retained coordinates, not preparation work. It can expand the grid past its existing cell cap. Grid crossing/overlap scoring also changes under coordinate subdivision. None of these limitations is resolved by the tiny fixture set.
|
||||
|
||||
Recommendation: finish the already-declared J/P/PL/L grid and stop coefficient/lane-spacing tuning on these fixtures. Retain L as an experimental option unless the final comparison supplies stronger value. The next useful acceptance scope is a frozen, modest set of independent scenes chosen before results: one realistic authored diagram with nested/folded content, one mixed-direction fan-in/out, and one moderately sized sparse diagram for routing time/budget behavior, including a fixed edge-order permutation. Choose a preferred traceability tradeoff explicitly; do not add architectural hooks merely to preserve this heuristic. Prioritize the explicit Layout command/reset contract and production integration lifecycle once a maintainable geometry choice is selected. No #32 closure or native readability acceptance follows here.
|
||||
|
||||
Bindings:
|
||||
|
||||
- P output SHA256 `13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
|
||||
- PL output `04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd`.
|
||||
- PL result.json `538aa79bcedd4cf646c63d5309ec738be4676e2045715db1035a4f334a536117`.
|
||||
- PL comparison JSON `81f57e651a8840aaaeacc085df2eb90174b2e494182f6cd40ccd6d50e7bb531e`.
|
||||
- PL contact audit JSON `60ce7e9735ceef50a92d29a0414aafe3d8fb6174dab99eff6397e2abc88e0afa` (inspected as independent worker evidence, not rerun here).
|
||||
@@ -0,0 +1,26 @@
|
||||
# P overlap-penalty experiment independent audit
|
||||
|
||||
Confirmed the reported finite result. Static read-only audit; no build, probe rerun, source edit or GUI action. P does not improve any of the nine layered candidate metric vectors and is not a demonstrated solution to their remaining shared routes.
|
||||
|
||||
Primary comparison: J06 `08656b18bf8934cf264469cf68fc6dea97c15cbb` versus P07 `3d7adff923dee5bed54dfdccc119dbee0c7c2773`. Inspected the latter commit: only routing.rs changes, overlap coefficient0.12→3.0 plus an experiment comment; cap80 remains unchanged. Both recorded `cargo run --locked --offline -p oa-core --example auto_layout_probe` receipts are Windows gnullvm/dev, exit0, inputs unchanged, failure null. Independently verified every log hash in both receipts.
|
||||
|
||||
Independent traversal of the raw outputs confirmed all37 variant Projects, projected nodes, projected ports and emitted route endpoint records match exactly. All nine layered candidates retain supported=true, repeat-input exactness, idempotence, passes2–10 equal first/previous, exact JSON/single-source roundtrips and identical conservation results. The authored-detour route-reset exception remains intentional. Baseline Command::Layout history/Undo checks remain identical; this is still not candidate-command Undo evidence.
|
||||
|
||||
Only two variant rows change numeric metrics:
|
||||
|
||||
| Original/before scene | Raw sharing J→P | Nonterminal sharing J→P | Bends | Length | Point contacts |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| crossed_bipartite |872→730|800→658|4→5|2064→2076|9→10|
|
||||
| two_containers_reversed_children |54→6|54→6|4→5|1512→1524|2→3|
|
||||
|
||||
Each extra contact is classified as a T contact in the separately generated independent interval audit: bipartite T3→4 and two-container T1→2; proper crossings remain0. Lower shared length therefore comes with one additional bend,12 length units and one additional point contact in each scene. Bipartite returns to the pre-J shared-length total; this does not establish trace readability. All baseline/reset rows, manual witness and nine layered scalar vectors are unchanged. Exact model/endpoint invariants do not imply identical polylines.
|
||||
|
||||
Evidence identities:
|
||||
|
||||
- J06 raw output `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f` (also identical to J03 output).
|
||||
- P07 raw output `13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
|
||||
- P07 result.json `6149122d05d77e02b463edb3dd359b06786bc4468c27d8cd625cbc1bc80c9894`.
|
||||
- P comparison JSON `9f228fbe78e1888c5d93e87dddd8d2effc01bab723929a87423c61e23f5cad66`.
|
||||
- P independent contact audit JSON `6f4add5c81f6d16c45efabbefd9e36c9beb637b6823993f0d51adc3e20485ad9`. Its recorded definitions and counts were inspected; this reviewer did not execute that helper again.
|
||||
|
||||
Recommendation: archive P as a bounded negative result for the layered overlap objective, preserving the two ordinary-scene tradeoffs. A predefined bounded lane-candidate experiment can now test whether available route geometry, rather than this single coefficient, limits improvement. Retain the same Projects/endpoints and all quality metrics; do not tune indefinitely against these nine fixtures or claim general quality/native acceptance. The cap, sequential edge order, fast-path preference, axis-only grid state and estimated label bounds remain limits.
|
||||
@@ -0,0 +1,47 @@
|
||||
# #32 bounded automatic-layout probe
|
||||
|
||||
Prepared `crates/oa-core/examples/auto_layout_probe.rs` in `.local/auto-layout-20260925` against reference source `715036e132677dd2bc2fb37ed316d93dc9987aec`. No production edits, compiler, Cargo, GUI or Gitea operation by this evaluator. Rustfmt parsed/formatted only the owned main example (`skip_children=true`). The separately owned `auto_layout_probe/layered.rs` is imported through its agreed `candidate(&Project, Id) -> Result<Project, ModelError>` interface; the evaluator does not use candidate internals to define fixtures, geometry metrics or expected conservation.
|
||||
|
||||
## Execution and output
|
||||
|
||||
From the worktree, in the parent's configured exclusive Windows toolchain environment:
|
||||
|
||||
```powershell
|
||||
cargo run --locked --offline -p oa-core --example auto_layout_probe > auto-layout-probe.jsonl
|
||||
```
|
||||
|
||||
The parent has `.local/run-auto-layout-check-20260925.py` for pinned receipt-based execution. Prefer that for recorded evidence; its source hash/commit must identify the actual build. The example's `reference_source` metadata is the investigation baseline, not a runtime attestation of checkout identity. Stdout is JSON Lines: one metadata/self-check record and nine fixture records. No output files, network calls or UI operations are performed by the example. Errors/unsupported candidates are explicit fields, not quality passes. There is no aggregate score or threshold; a zero metric is not a readability or hard-safety certification.
|
||||
|
||||
Each fixture emits the original and current `Command::Layout` Projects and real projected/routed geometry. It also emits the same observations for a **reset-only control applied after existing Layout**, and for the separately implemented experimental candidate invoked on the original Project. The control clears only waypoints and label placement on visible routed edges whose geometry is not suspended/promoted, retaining endpoint attachments, hidden/promoted records and empty route records. The candidate does not determine this control. Ten successive existing Layout calls and ten successive candidate calls are each compared with their preceding and first result, stopping with an explicit error if needed. Candidate identical-input repeat and one further application are also compared separately. Reset eligibility is measured after baseline Layout; the candidate freezes it before Layout. These all-visible fixtures do not change visibility, so broader eligibility-equivalence claims are deferred.
|
||||
|
||||
## Declared fixtures
|
||||
|
||||
1. Four-node flat chain, initially left to right.
|
||||
2. Seven-node chain, initially left to right, exposing four-column row wrapping if present.
|
||||
3. Diamond with branch/join semantics and declared two-level positions.
|
||||
4. Crossed bipartite ordering, including both straight and crossed pairings.
|
||||
5. Parent Function with two child Functions, internal exchange and exchange to an outside Function.
|
||||
6. Two-node authored high detour with a far label offset; reset-only isolates stale constraint cost.
|
||||
7. Two-node exchange with explicit source-Left0.3 and target-Right0.7 port anchors.
|
||||
8. Two parent Functions, each with two children, and reversed inter-parent pairings. A separate predeclared witness swaps only right-child y positions, aligning each source with its target. Its real routing is measured; no zero-crossing result is assumed.
|
||||
9. Three Functions with long ordinary exchange names, including a bypass; the actual existing summary/name excerpt bounds are observed.
|
||||
|
||||
Project, diagram, Function, placement, relation and automatically created port UUIDs are remapped to stable IDs in creation order. Port aliases are reset explicitly. Names and other aliases are unique per fixture, avoiding random-ID tie dependence. The fixture Projects in output allow independent repetition and offline visualization; projected node rectangles/ports and per-edge routed point sequences/label rectangles are also included.
|
||||
|
||||
## Metric definitions and exclusions
|
||||
|
||||
- **Proper crossings:** unique intersection locations per distinct edge pair, interior to both straight segments. Locations deduplicate at0.0001 world units. Segment endpoints, bend contacts, T junctions and collinear overlaps are excluded from this count. Raw crossings remain the primary count. A separate nonterminal count subtracts only contacts within `PORT_STUB` of a physically equal endpoint with the same projected owner, where both tested segments are terminal. Entire compacted first/last segments are never exempt.
|
||||
- **Shared runs:** summed pairwise collinear overlap length, reported separately from crossings. Raw length is primary. Common exact endpoint terminal overlap gets a separately reported exemption bounded by `PORT_STUB` per common endpoint, capped by the overlap. Three overlapping edges contribute three pairwise overlaps; retraced segments may contribute multiplicity. This is not union length.
|
||||
- **Unrelated node collisions:** positive rectangle intersection area for distinct nodes; ancestor/descendant pairs are exempt from this count. No inferred intent is attached to a reported collision.
|
||||
- **Label/node collisions:** positive intersection of real routed label bounds with projected node rectangles, including endpoint nodes. A label wholly inside an endpoint ancestor's *body below the header* is exempt; overlap with its header remains reported. Ordinary header height is64; dedicated State height uses the core helper. Border crossings are retained. These conservative boxes are not glyph measurements.
|
||||
- **Edge/node penetration:** per edge/node pair, positive clipped segment length in unrelated node interiors. Endpoint-owner nodes are exempt; endpoint ancestors contribute only their header obstacles, so intentional passage through container bodies/boundaries is not counted. This does not detect re-entry into an edge's own endpoint node.
|
||||
- **Label/stroke intersection:** positive clipped length of another edge's stroke inside a label rectangle, one record per label-edge/stroke-edge pair. Own-edge strokes are excluded; an intentional anchor/label association is not declared a defect. Stroke thickness, arrowheads and antialiasing are unmodeled.
|
||||
- **Other observations:** actual routing warnings and details; routed total length; direction-changing bends including reversal; total drawing bounding-box area (including labels/nodes); real node/port/edge geometry. Area is scale-sensitive and is not minimized at the expense of crossings or readability.
|
||||
|
||||
Tiny analytic assertions check proper crossing versus endpoint contact, collinear overlap versus separated lines, rectangle contact, and line/interior clipping. They will run with the example, but have not been executed by this author. Geometry tolerance is0.0001 world units, while proper-intersection parameter/parallel checks use1e-9.
|
||||
|
||||
## Conservation and limits
|
||||
|
||||
The current command is exercised through `Session`, with exact one-step Undo/Redo and history/no-op checks. Full JSON decode and formatted single-source parse round trips are compared to the complete Project before/after; these do not prove original multi-file comments/byte preservation. Semantic records, target-view nongeometry fields, other views, per-node identity/visibility/port anchors and authored routes are reported separately. Reset/candidate route equality may intentionally be false and must be assessed against their stated reset policy, not silently treated as semantic loss.
|
||||
|
||||
Folded/filter/hidden-route preservation is implemented in the reset eligibility check but not independently falsified by these nine fixtures. Dedicated State #36 native typography, dense stress, cycles, disconnected large sets, non-planar crossing lower bounds, self-crossings, self-loops, full stroke geometry and interactive cognitive load are absent. The candidate may explicitly reject unsupported cases. No algorithm can promise crossing-free output for arbitrary non-planar graphs; the paired-container witness only establishes a concrete alternative ordering to examine. Use vector observations and the output geometry to diagnose mechanisms before selecting a candidate; this is a bounded experiment, not a production layout-quality framework or native acceptance.
|
||||
@@ -0,0 +1,27 @@
|
||||
# #32 first diagnostic probe review
|
||||
|
||||
**No blocking finding for compiling/running the current finite experiment.** This is a source/evaluator-validity review, not production acceptance or a claim the candidate improves layout. Nine small deterministic FunctionalDataflow fixtures support a bounded comparison; later scope gaps should not delay this run. No compiler, GUI, helper, source edit or Gitea operation performed.
|
||||
|
||||
Reviewed snapshot SHA256: auto_layout_probe.rs `72d850fdd9aad65788004949380c28cba48a0c2be3dc28f3aef3900c7f8724c7`; auto_layout_probe/layered.rs `bda9a59968b4b0e284e8e1393eb86c90cdf0d856d5f9830ae3c6fc0043df839a`. The evaluator worker is separately finalizing candidate repetition reporting; later edits require a scoped diff check, not relabeling this reviewed snapshot.
|
||||
|
||||
## Evaluator validity
|
||||
|
||||
Raw strict-interior segment crossings and pairwise collinear shared length are primary outputs, with crossing coordinates deduplicated per edge pair. Endpoint sharing is not exempted wholesale: secondary figures subtract only bounded common physical tip lengths. Node/header, label/node, label/label and unrelated stroke/label measurements remain separate. Analytic primitive checks cover a proper crossing, endpoint touch, collinear overlap, disjoint parallel segments, rectangle touch and inside-length boundary. Complete before/after models and routed points are emitted, permitting independent examination beyond scalar totals. No quality threshold or automatic overall-pass field promotes a poor drawing to acceptance.
|
||||
|
||||
Fixture IDs are normalized before use; semantic port IDs/aliases are also stabilized. The manual reversed-child witness is separately authored and measured, not generated from candidate output. It must still be read as a witness with its reported validation/geometry, not an asserted universal optimum. Standard parse/JSON roundtrip and old-Layout history checks are meaningful within their named scope.
|
||||
|
||||
## Actionable limitations to retain when interpreting this run
|
||||
|
||||
1. **Reset control eligibility:** reset_effective_routes receives the already arranged Project, whereas layered candidate freezes its eligible set before Layout. For these all-visible, uncollapsed fixtures, Layout does not change membership/promotion, so this does not invalidate the current comparison. Freeze the original eligible IDs for future folded/filtered cases; do not generalize current equivalence.
|
||||
2. **Conservation granularity:** semantic/other-view/node-metadata checks are independent and useful. target_view_nongeometry_exact restores all routes and layout before comparing; authored_routes_exact will intentionally become false. Those fields do not separately prove attachment preservation, invisible-route retention or a no-change layout field. Add targeted comparisons before making those claims on future fixtures. The current prototype source copies original route records and only clears eligible waypoints/labels, then translates retained routes, so no observed source-level violation was found here.
|
||||
3. **History scope:** undo_exact/one_step_undo/redo_exact exercise existing Command::Layout through Session only. The layered candidate is a pure Project transformer, not an integrated command and has no tested operation/history lifecycle. Its repeat-same-input and second-call comparison are useful; ten-call candidate stability was pending in this snapshot. Do not describe baseline ten_layout_calls as candidate stability.
|
||||
4. **Metric coverage:** strict proper crossings deliberately exclude T contacts and intersections at segment bends; pairwise shared length counts segment-pair traversal multiplicity, not geometric union length. No candidate should be selected solely by one scalar if it shifts crossings into uncounted touches. Endpoint-owner interiors are excluded from unrelated-edge penetration, and label/stroke excludes its own edge. These are declared definitions, not proof of complete route validity. Association-end labels, actual glyph ink, State multiline measured bounds and port labels are not covered by current primary label metrics. Current nine fixtures contain functional exchanges, so these omissions do not corrupt their narrow comparison.
|
||||
5. **Fixture coverage:** all current fixture families are small SA FunctionalDataflow cases. Other-view exactness is vacuous where only one view exists; folding, filtering, omitted-node, State, Allocation, Scenario, undirected cycles, dense scaling, UI admission and multi-file source conservation are not established. Preserve these gaps explicitly rather than broadening the initial run unnecessarily.
|
||||
|
||||
## Prototype source risks the experiment should expose
|
||||
|
||||
The candidate preserves semantic records and route-list order, retains attachments/port anchors, rejects folded/omitted topology explicitly, and uses stable alias/ID order, deterministic cycle fallback, a graph limit and counted ordering work. Derived corners are not persisted as hard pins. No product file is replaced.
|
||||
|
||||
Three passes use frozen per-call minima, but those minima come from baseline Layout using the input's existing sizes; cross-call size ratcheting remains possible and should appear in repeated full-Project comparison. Global maximum label width controls every sibling gap, so one long label may balloon unrelated layout area. Incoming-neighbor ordering can improve the reversed-container fixture without proving general crossing reduction; undirected edges do not constrain ranks/order. The work budget excludes existing projection/routing work and several collections, so it bounds selected prototype loops, not total CPU complexity. With current small fixtures these are diagnostic candidate weaknesses, not reasons to prevent the run.
|
||||
|
||||
Interpret a failed invariant, growing repeated layout, worse collisions or huge area as evidence against this prototype. Preserve errors and unsupported statuses; do not use successful process exit as layout-quality acceptance. Decide further work from the produced geometry and independent metric vector. Production integration, complete command/source/API/history behavior, native readability and broader issue32 acceptance remain separate.
|
||||
@@ -0,0 +1,75 @@
|
||||
"""Render recorded probe geometry for inspection; this is not a desktop screenshot.
|
||||
|
||||
Usage: python render_probe.py PROBE_STDOUT_JSONL NEW_OUTPUT_DIRECTORY
|
||||
Uses one scale across every result for each fixture; input geometry is unchanged.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
def geometries(value, name=""):
|
||||
if not isinstance(value, dict):
|
||||
return
|
||||
if "routed_edges" in value and "projected_nodes" in value:
|
||||
yield name, value
|
||||
return
|
||||
for key, child in value.items():
|
||||
yield from geometries(child, f"{name}.{key}".strip("."))
|
||||
|
||||
|
||||
source, output = map(Path, sys.argv[1:])
|
||||
output.mkdir(parents=True, exist_ok=False)
|
||||
font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", 13)
|
||||
files = []
|
||||
for line in source.read_text(encoding="utf-8").splitlines():
|
||||
item = json.loads(line)
|
||||
fixture = item.get("fixture")
|
||||
if not fixture:
|
||||
continue
|
||||
variants = list(geometries(item))
|
||||
if not variants:
|
||||
continue
|
||||
largest_width = max(g["drawing_bounds"]["size"]["width"] for _, g in variants)
|
||||
largest_height = max(g["drawing_bounds"]["size"]["height"] for _, g in variants)
|
||||
scale = min(1.0, 1140 / max(1, largest_width), 690 / max(1, largest_height))
|
||||
for name, geometry in variants:
|
||||
canvas = Image.new("RGB", (1200, 800), "white")
|
||||
draw = ImageDraw.Draw(canvas)
|
||||
origin = geometry["drawing_bounds"]["position"]
|
||||
|
||||
def point(position):
|
||||
return (30 + (position["x"] - origin["x"]) * scale,
|
||||
70 + (position["y"] - origin["y"]) * scale)
|
||||
|
||||
def rectangle(position, size):
|
||||
x, y = point(position)
|
||||
return x, y, x + size["width"] * scale, y + size["height"] * scale
|
||||
|
||||
draw.text((20, 12), f"{fixture} / {name} | geometry only, not native UI", font=font, fill="black")
|
||||
draw.text((20, 32), f"Fixed fixture scale {scale:.4f}; text below identifies bounds, not glyph measurements", font=font, fill="black")
|
||||
for node in sorted(geometry["projected_nodes"], key=lambda n: (n["depth"], n["id"])):
|
||||
box = rectangle(node["position"], node["size"])
|
||||
draw.rectangle(box, fill="#eef2f6", outline="#687787", width=1)
|
||||
draw.text((box[0] + 3, box[1] + 3), node["id"][-5:], font=font, fill="#334155")
|
||||
for edge in geometry["routed_edges"]:
|
||||
points = [point(p) for p in edge["points"]]
|
||||
if len(points) > 1:
|
||||
draw.line(points, fill="#245c88", width=2)
|
||||
label = edge["label"]
|
||||
if label["text"]:
|
||||
box = rectangle(label["position"], label["size"])
|
||||
draw.rectangle(box, outline="#ad5715", width=1)
|
||||
target = output / f"{fixture}-{name.replace('.', '-')}.png"
|
||||
canvas.save(target)
|
||||
files.append({"name": target.name, "bytes": target.stat().st_size,
|
||||
"sha256": hashlib.sha256(target.read_bytes()).hexdigest(), "scale": scale})
|
||||
(output / "manifest.json").write_text(json.dumps({
|
||||
"input_sha256": hashlib.sha256(source.read_bytes()).hexdigest(),
|
||||
"renderer_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
|
||||
"scope": "Offline schematic of recorded core geometry; no native or font-rendering acceptance.",
|
||||
"images": files}, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"Rendered {len(files)} geometry records without modifying the probe output.")
|
||||
@@ -0,0 +1,66 @@
|
||||
# #32 automatic arrangement: bounded research
|
||||
|
||||
Prepared 2026-09-25; local research, not an accepted design or implementation review. No compiler, GUI, helper, or remote mutation was run. Primary sources were read online. Local source spot-check: clean `.local/auto-layout-20260925`, commit `715036e132677dd2bc2fb37ed316d93dc9987aec`. Parent owns current implementation mapping and contract selection.
|
||||
|
||||
The user needs Arrange to generate/remove bends, reduce connection intersections, and account for connection labels, while retaining meaningful nested containment/deployment. A useful solution therefore needs coordinated node ordering, space allocation, routing, and label placement. Merely sorting boxes or clearing existing waypoints cannot establish success.
|
||||
|
||||
## Verified precedents and their limits
|
||||
|
||||
**Capella workflow.** Capella 7 release notes document Layout Children, temporary movement of pinned elements, and renaming Arrange All/Selection to Layout All/Selection. This supports making operation scope and preservation of manual organization explicit. It does **not** establish that Capella uses ELK as its default engine. [Official Capella 7 notes](https://github.com/eclipse-capella/capella/wiki/Release-Notes-7.0.0).
|
||||
|
||||
**Sirius workflow.** Its user guide describes avoiding overlap, fitting containers around contents, attempting fewer edge crossings, and preserving pinned locations. Layout Children operates at the immediate level. A selected container can have its contents arranged while its location remains fixed. The guide also describes simplifying an unpinned edge between pinned endpoints. However, its pinning section and later toolbar section disagree about edge pinning support; do not copy that ambiguity into ARCADIA's contract. [Sirius user guide](https://eclipse.dev/sirius/doc/user/diagrams/Diagrams.html). Sirius documents configurable default/composite and ordered-tree layouts, with ELK as an additional integration described as experimental. Availability of that integration is not evidence of a particular Capella installation's behavior. [Sirius layout configuration](https://eclipse.dev/sirius/doc/specifier/diagrams/Diagrams.html).
|
||||
|
||||
**ELK capabilities.** ELK Layered explicitly supports orthogonal routing, ports, labels, compound graphs, and cross-hierarchy edges with suitable configuration. [Algorithm reference](https://eclipse.dev/elk/reference/algorithms/org-eclipse-elk-layered.html). `INCLUDE_CHILDREN` allows a joint run through descendants; the root default otherwise separates children. Independent child layout is therefore not equivalent to globally considering connections across nested containers. [Hierarchy handling](https://eclipse.dev/elk/reference/options/org-eclipse-elk-hierarchyHandling.html). Port constraints distinguish free placement, fixed side/order/ratio, and fixed position. [Port constraints](https://eclipse.dev/elk/reference/options/org-eclipse-elk-portConstraints.html).
|
||||
|
||||
The authors describe a Sugiyama-family layered algorithm, constrained barycenter crossing minimization, size/port-aware coordinate assignment, and separate support for compound graphs and disconnected components. These are heuristics with configurable priorities, not a guarantee of globally minimal crossings. [ELK authors, GD 2024](https://drops.dagstuhl.de/storage/00lipics/lipics-vol320-gd2024/LIPIcs.GD.2024.56/LIPIcs.GD.2024.56.pdf).
|
||||
|
||||
**Routing is a distinct problem.** Wybrow, Marriott, and Stuckey describe orthogonal visibility graphs, A* route search, and ordering/nudging of shared segments. Their bend/length optimality statement concerns individual routes under their model, not joint optimal placement of all nodes, labels, and connectors. [Orthogonal Connector Routing, GD 2009](https://people.eng.unimelb.edu.au/pstuckey/papers/gd09.pdf). libavoid exposes penalties for crossings, segments, cluster crossings and shared paths, plus endpoint direction constraints. It supplies routing rather than a complete node arrangement solution. [libavoid API](https://www.adaptagrams.org/documentation/namespaceAvoid.html).
|
||||
|
||||
## Materially different approaches
|
||||
|
||||
| Candidate | Practical proposal for this project | Main advantage | Main risk / decisive falsifier |
|
||||
| --- | --- | --- | --- |
|
||||
| Native Rust layered arrangement + existing router | Build a bounded, deterministic placement pipeline over the projected hierarchy; reserve measured label space and improve routes after placement. | Best match to Rust preference, existing model/history, and deployment; reuse current geometry. | Nested cross-boundary routes and label congestion make a supposedly small implementation grow. Reject if the finite compound fixtures require ad hoc per-diagram exceptions or cannot reduce known avoidable crossings. |
|
||||
| ELK Layered through elkjs | Translate one immutable projected graph to ELK JSON, run a pinned bundled JS engine off the UI thread, validate results, apply a presentation transaction. | Mature joint treatment of ports, labels, layering and hierarchy. | Adds runtime/distribution/adapter cost. Reject if exact port semantics, nested coordinates, measured label boxes, bounded cancellation, or Windows/Linux packaging cannot be demonstrated. |
|
||||
| Preserve nodes; improve routes and label locations | Use existing Rust routing plus bounded rerouting/order search, or investigate libavoid through FFI. | Least disruption to the user's spatial organization; useful separate Reroute command. | Cannot untangle crossings imposed by node/port ordering. Insufficient as the sole Arrange implementation if an order swap solves a fixture it cannot improve. |
|
||||
|
||||
elkjs is the official JavaScript form of ELK's layout algorithms, consumes/returns graph geometry, and supports worker execution. Using the distributed JavaScript does not require a Java runtime. A Rust embedding still needs an explicitly selected JS runtime or packaged process; compatibility, footprint, cancellation and licensing must be checked in a bounded spike. It is not a Rust library or a ready Iced integration. [elkjs repository and API](https://github.com/kieler/elkjs).
|
||||
|
||||
Graphviz is a possible comparison baseline, not my preferred default: its current official `splines=ortho` documentation explicitly says this routing does not handle ports or, for dot, edge labels. That limitation directly intersects this task. A separate router/label solver could repair the integration, but removes much of its simplicity. [Graphviz splines](https://graphviz.org/docs/attrs/splines/). Force/stress layout is another possible overview style, but I would not spend the first experiment on it: engineering flow direction, nesting and endpoint constraints still need substantial machinery afterward. This is a fit judgment, not a claim those algorithms cannot be extended.
|
||||
|
||||
## Proposed minimum contract, independent of engine
|
||||
|
||||
1. **Operate on diagram presentation.** Preserve semantic identities, relation direction, containment/deployment, port identity and connectivity, node/edge membership, and label text. Layout cycle breaking must never reverse the actual model relation. Projected parentage, not an independently guessed semantic tree, defines nesting. Hidden/collapsed content must have a declared policy; do not silently expose it.
|
||||
2. **Define scope before implementation.** Initial whole-diagram Arrange is simpler than arbitrary selection. If selection is included, decide whether a container means its immediate children or its full subtree, whether it can grow, and how boundary-crossing edges update. Outside nodes remain fixed. Do not infer support for selection from a whole-graph solver.
|
||||
3. **Define replaceable geometry.** Explicit Arrange may replace the in-scope route waypoints, creating useful bends and removing redundant ones. Decide independently whether authored endpoint attachments and authored label placement are preserved or reset. Recommended initial rule: preserve semantic/fixed attachments; authorize replacement of bend geometry; treat preserved label boxes as constraints. Do not retain stale absolute label offsets accidentally after wholesale rearrangement. Parent must settle this user-visible policy.
|
||||
4. **Measure before arranging.** Supply visible node dimensions, headers, port/row areas, label rectangles and clearance in world units. Use the same prepared text and measurement as painting, including multiline labels and fallback glyphs. Feed label occupancy into spacing/routing, then validate the final rendered geometry. Fitting labels only after arranging boxes can recreate collisions.
|
||||
5. **Atomic application.** Return a candidate presentation delta, validate it, then create one Undo entry. Failure/cancellation leaves the model unchanged. Undo restores complete prior geometry; Redo and save/reopen reproduce the result. A stale asynchronous result must not overwrite edits made since its input snapshot.
|
||||
6. **Quality, not an impossible universal promise.** Require no invalid geometry, prohibited node/header penetration, or lost constraints. Minimize avoidable crossings, label collisions and shared-path ambiguity before compactness and bend count. Preserve a satisfactory baseline when candidates are worse. Hard constraints may make a zero-collision drawing impossible; report the residual rather than claiming success from a cost scalar.
|
||||
|
||||
The local spot-check explains one important seam: `crates/oa-core/src/session.rs::layout` already obtains `projection::parents`, recursively sizes nested nodes and rejects Scenario geometry. `routing.rs` explicitly distinguishes persisted authored pins from bounded derived routes. Generated bends need not all become persisted manual pins: persist the chosen presentation change according to a declared regeneration policy. The #36 successor's measured State labels must be reconciled when integrating; this base predates it. No claim about uninspected callers or final API follows from this spot-check.
|
||||
|
||||
## Native Rust candidate: finite algorithm experiment
|
||||
|
||||
This is a proposal, not an implementation prescription. Build a temporary layout graph with stable IDs, measured boxes, containment, real port constraints and typed edges. Determine feedback edges for cycles without modifying semantics; assign layers; insert temporary long-edge/label placeholders; perform a fixed number of alternating barycenter/median sweeps with adjacent swaps accepted only when crossing cost improves; assign non-overlapping coordinates. Lay out children with explicit boundary connection ordering and reserve parent headers/port areas. Bottom-up subtree packing alone is a baseline, not proof of cross-hierarchy quality.
|
||||
|
||||
Route orthogonally around the resulting obstacles, with penalties for bends, crossings and excessive shared paths. Place measured labels in reserved corridors; if conflicts remain, permit a bounded spacing/rerouting pass. Remove duplicate and collinear intermediate vertices. Keep separate metrics for edge crossings, shared-path length, label collisions, bends, area and displacement so a shorter route cannot disguise a newly unreadable diagram. Stable tie-breaking, bounded passes and retaining the best valid candidate limit oscillation and cost. Compare this candidate against the same finite fixtures processed by elkjs before investing in a general framework.
|
||||
|
||||
## Falsifiers and finite milestones
|
||||
|
||||
**First: freeze the evaluator and geometry policy.** Six small fixtures are enough to expose foundational errors: (a) a two-layer order swap with a known crossing-free solution; (b) a diamond plus cycle/self-loop; (c) a two-level OA containment graph with internal and cross-container connections; (d) SA deployment nesting with fixed semantic ports and high-degree fan-out; (e) long/multiline labels in a tight corridor; (f) disconnected components, collapsed content and an already tidy layout. Include one route needing added bends and one needing removed bends. If scope excludes any fixture feature, state that before scoring.
|
||||
|
||||
Count proper interior intersections between distinct routed edges separately from collinear overlaps. Exclude common endpoint contact, but do not exempt edges merely because they share a source: an intersection elsewhere still counts. Count label-label and label-unrelated-edge/node intersections; intentional own-edge label contact and container background containment need specific exemptions. Check allowed container boundary passages rather than counting every containment-border crossing as an error. Record scores on final routes, not only straight-line layer proxies.
|
||||
|
||||
**Second: choose using measured results.** For the known solvable fixtures, demand the known crossing/collision target, semantic equality, correct port attachment and legal containment. Test deterministic repetition, a second Arrange reaching a stable result, and small perturbations not causing unbounded growth. Include invalid inputs/work-budget exhaustion; preserve the input on failure. Set an interactive-time budget against a declared representative model size and hardware before timing, rather than inventing a universal threshold here.
|
||||
|
||||
**Third: verify the real workflow.** Parent performs Arrange, inspects routes and labels at normal reading zoom, Undo, Redo, save and fresh reopen on OA and SA models. Check that connections remain traceable and nesting still conveys the intended relationship; aggregate crossing counts alone do not establish readability. No such execution or acceptance is claimed by this research.
|
||||
|
||||
Recommended next decision: settle reset/preservation of bends, endpoint attachments and label anchors, then compare the native layered candidate and elkjs on the same compound, port-and-label fixtures. Route-only improvement is a useful fallback capability but should not silently redefine the user's Arrange request.
|
||||
|
||||
## Parent's current code findings: implication for the first experiment
|
||||
|
||||
Parent reports that the existing router already has deterministic bounded orthogonal search, obstacle exclusion, crossing/shared-run penalties and automatic label collision sampling; current Arrange uses a four-per-row root placement after topological/alias ordering. These are parent-provided inspection findings, not independent runtime verification here. They materially favor **reuse of existing routing plus improved node arrangement** as the first candidate, rather than reimplementing routing or immediately adopting another engine. Feed its final-route metrics back into a bounded choice among placement candidates; label sampling alone still cannot create missing corridor space.
|
||||
|
||||
Parent's proposed policy—preserve semantic ports, authored port anchors and endpoint attachment preferences; reset only visible effective bends/label overrides during explicit full Auto-layout; retain hidden/promoted metadata; leave automatic elbows derived—is a coherent candidate. Its key falsifier is visibility scope: a folded/proxy edge must not cause deletion of dormant metadata belonging to a hidden original endpoint/route. Define “visible effective” by exact original edge ID plus unsuspended geometry, not just membership in the rendered edge list. Test folded then expanded diagrams, ancestor-promoted endpoints, partially visible authored routes and a visible label whose anchor was inherited. If retained dormant metadata becomes effective on expansion, the restored manual shape is expected under this policy and should not be advertised as newly automatically arranged. Explicit full Auto-layout can reasonably reset visible label overrides because its stated purpose authorizes rearrangement, but ordinary redraw, drag and routing must not acquire that reset behavior.
|
||||
|
||||
Compare reuse against elkjs only after scoring this bounded candidate. A successful existing-router experiment removes much of the justification for another runtime; persistent compound/port-order failures would supply concrete reasons to reopen engine adoption. The newly observed untracked `harness/auto-layout-investigation-20260925.md` in the worktree is parent work; this research did not modify it or product source.
|
||||
@@ -0,0 +1,51 @@
|
||||
# #32 residual routes after terminal-join candidate J
|
||||
|
||||
Read-only diagnosis of run03 `command/output.log`, `.local/auto-layout-j-comparison-20260925.json`, the geometry-only crossed-bipartite PNG, and current `routing.rs` / `projection/port_layout.rs`. No edits, builds or native GUI execution. J is an experimental cost correction, not an accepted readability improvement for every scene.
|
||||
|
||||
## The remaining187 units are not coincident distinct ports
|
||||
|
||||
The four functional exchanges deliberately reuse four semantic ports:
|
||||
|
||||
| Flow | Source port | Target port |
|
||||
| --- | --- | --- |
|
||||
| 0 (`009`) | `010` | `014` |
|
||||
| 1 (`00c`) | `013` | `011` |
|
||||
| 2 (`00f`) | `010` | `011` |
|
||||
| 3 (`012`) | `013` | `014` |
|
||||
|
||||
Projected source ports are `(264,106)` and `(264,286)`; target ports `(346,106)` and `(346,286)`. Each port is a single real semantic identity serving two edges. There are no authored port anchors in this fixture. The route endpoints and ports were unchanged by J. Splitting a common port into several displayed ports or changing relation port IDs would change the contract/semantics and is not a routing remedy.
|
||||
|
||||
Of187 pairwise shared units,72 are four legitimate common-port18-unit terminal stubs. The remaining115 are four avoidable interior overlaps:
|
||||
|
||||
- Flow0/Flow2: `y=106, x=282..328`, length46.
|
||||
- Flow1/Flow2: `y=106, x=305..328`, length23.
|
||||
- Flow1/Flow3: `y=286, x=282..305`, length23.
|
||||
- Flow0/Flow1: `y=106, x=305..328`, length23. These routes have different endpoints, so this is not a common-port exemption.
|
||||
|
||||
These sum115. The two diagonals now have separate vertical channels (`x=328` and `x=305`); horizontal tails still merge different routes. The geometry PNG confirms that a user sees shared horizontal lines with branch contacts, not four independent readable connections. It is not native/glyph evidence.
|
||||
|
||||
`port_layout::layout` chooses automatic sides from peer centers, semantic fallback and clear exits; explicit anchors override the resulting side/offset. It sorts multiple automatic ports on a side by peer-axis coordinate and ID, then allocates distinct positions around fixed anchors. Here each node has only one relevant port, so improving distinct-port separation would not address this fixture. Moving a common automatic port could alter geometry but still leaves all its incident edges sharing the same physical endpoint. Fixed anchors must remain exact.
|
||||
|
||||
## J trades one objective against another
|
||||
|
||||
J improves layered diamond overlap82→36 (nonterminal0) and layered bipartite344→187 (nonterminal115). But the original unarranged bipartite regresses730→872 shared units (nonterminal658→800), while bends5→4 and length2076→2064. The current original routes use a320-unit top horizontal trunk and a160-unit second-diagonal tail; later straight edges overlap those trunks. This is consistent with a length/bend-biased objective, not evidence that J universally improves routing.
|
||||
|
||||
`crossing_cost` charges only0.12 per shared unit, capped80 per prior segment; a turn costs24. J now compares more complete turn costs, so it can rationally prefer a cheaper route with more overlap. The router evaluates edges in stable-ID order and does not jointly revise earlier paths. Terminal fairness alone cannot correct an objective that undervalues ambiguous shared strokes. Public/ordinary scenes must remain in the comparison; do not judge only Arrange-generated geometry.
|
||||
|
||||
## Next bounded experiment: penalty versus available lanes
|
||||
|
||||
Recommend a tiny factorial comparison with node positions, ports, anchors and edge order frozen: J; J+P; J+L; J+P+L. Keep the original unarranged bipartite as a named regression sentinel alongside layered diamond/bipartite and the existing corpus. This separates missing candidate geometry from cost preference; no placement change initially.
|
||||
|
||||
**P:** use one predeclared experimental overlap coefficient, e.g.3.0 instead of0.12, retaining the80 per-segment cap and proper-crossing24 initially. This is a falsifier, not a proposed final default. A12-unit dogleg around a straight shared span can cost24 additional length plus96 for four full-path turns. The cheap existing coefficient cannot compensate for that; even3.0 with the80 cap may still reject it. Record this failure explicitly rather than repeatedly tuning. A second experiment removing/changing the cap would require separate justification; the cap and segment subdivision make the objective unlike a simple global shared-length weight.
|
||||
|
||||
**L:** offer a bounded number of parallel candidate coordinates at `CLEARANCE=12` on either side of occupied horizontal/vertical segments, subject to current obstacle clearance and fixed terminal stubs. These are derived path candidates, never authored waypoints. Put them in fast-path candidate space and, if needed, the grid space consistently, with a deterministic global cap. The current obstacle-boundary/midpoint coordinate set does not systematically offer these close parallel lanes. More space between boxes alone cannot supply the missing candidate coordinate or change its cost preference.
|
||||
|
||||
A smaller staging of this comparison is to run P first and inspect actual chosen alternatives, then add L only if the recorded candidates lack the desired lane. Do not silently combine penalty, cap, edge ordering and node spacing changes. If P merely creates crossings/long exterior detours, that disproves it as a standalone improvement. If L offers legal lanes but they are never selected, that isolates the objective. The result may justify a different explicit priority or bounded shared-segment nudge, but not before this evidence.
|
||||
|
||||
**Alignment control:** an additional fixed24-unit inter-layer gap or stagger is lower priority. It changes the diagram and automatic peer positions, complicates attribution, and can lengthen shared trunks. Alignment may be useful for a particular placement heuristic, but it is not a direct explanation of identical horizontal tails between the same common ports. Port-placement changes are outside the identified dependency scope.
|
||||
|
||||
## Acceptance constraints for the experiment
|
||||
|
||||
Keep exact semantic graph, port identities, attachments, authored anchors and generated-versus-authored route distinction. Report raw overlap, legitimate terminal overlap, nonterminal overlap, proper crossings AND branch/bend contacts, labels, obstacles, length, turns, warnings and workload. Current proper-crossing zero excludes contacts at bends; trading coincident strokes for distinct, obvious crossings can improve traceability even if that one metric rises. Conversely, tiny offsets that appear merged at normal zoom are not success.
|
||||
|
||||
Use shared-port fan-out/fan-in and distinct-port controls, fixed-anchor controls, narrow corridor, authored-pin and opposite-direction routes. Compare original, reset-only and layered scenes, plus a fixed edge-ID permutation to expose priority sensitivity. Parent should inspect actual route tracing at normal zoom before adopting any weight/lanes policy. No quality acceptance or port-placement defect is asserted here.
|
||||
@@ -0,0 +1,106 @@
|
||||
# First automatic-layout experiment
|
||||
|
||||
## Decision
|
||||
|
||||
Retain the hierarchy/label-spacing prototype for further experiments; do not
|
||||
adopt it as production Auto-layout. It improves several named fixtures beyond
|
||||
resetting old bends, but regresses shared connector length in two fixtures.
|
||||
Shorter routes and zero proper crossings do not establish readable connections.
|
||||
The next experiment should isolate route selection at fixed node positions,
|
||||
before adding more node spacing or replacing the existing routing engine.
|
||||
|
||||
## Method and receipt
|
||||
|
||||
Tested source `e7deea7039bcf31675cffbb462cfeb19d62a7e20`, based on released
|
||||
`715036e132677dd2bc2fb37ed316d93dc9987aec`. No production file changed in that
|
||||
commit. Windows x86_64-pc-windows-gnullvm, Rust 1.98.1, LLVM mingw, one Cargo job,
|
||||
incremental compilation disabled; Linux excluded. Command:
|
||||
|
||||
```text
|
||||
cargo run --locked --offline -p oa-core --example auto_layout_probe
|
||||
```
|
||||
|
||||
The recorded runner completed at 2026-09-25T00:42:06Z, exit 0, unchanged inputs,
|
||||
no recorded failure. stderr contains only compile/run progress. This means the
|
||||
diagnostic process completed, not that layout quality passed. The JSONL has one
|
||||
metadata record and nine fixture records, with full input/result Projects and
|
||||
core route geometry. Its SHA256 is
|
||||
`21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`.
|
||||
|
||||
[Evidence archive](run-01/probe-e7deea70.zip), 900995 bytes, SHA256
|
||||
`c52f82d4782cd6a7f8cbe67498c8b2371e99204a65976aa8bcbbd0a86f835069`,
|
||||
contains original receipts, source inventories, output, runners and 37 offline
|
||||
geometry PNGs. [Manifest](run-01/manifest.json) binds every member and the
|
||||
post-run executable identity. All archive members were byte-compared to the
|
||||
local originals. Original absolute paths describe this machine; reproduce using
|
||||
the source commit and command above, with a suitable Windows Rust toolchain.
|
||||
|
||||
## Observations
|
||||
|
||||
Values below compare existing Layout with the layered prototype. Reset-only
|
||||
matches existing Layout except for the authored-detour fixture, where it already
|
||||
reduces length to 240, bends to zero and area to 90816. Shared length is pairwise
|
||||
segment overlap, not the union of occupied space; area uses recorded bounds.
|
||||
|
||||
| Fixture | Shared length | Label/node collisions | Route length | Bends | Area |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||
| Four-node chain | 0 → 0 | 0 → 0 | 720 → 246 | 0 → 0 | 213312 → 150744 |
|
||||
| Seven-node chain | 0 → 0 | 0 → 0 | 2560 → 492 | 8 → 0 | 523584 → 271920 |
|
||||
| Diamond | 36 → 82 | 0 → 0 | 2200 → 688 | 8 → 4 | 300576 → 260832 |
|
||||
| Crossed bipartite | 276 → 344 | 0 → 0 | 3284 → 688 | 12 → 4 | 300576 → 165360 |
|
||||
| Nested cross-boundary | 0 → 0 | 1 → 0 | 1076 → 364 | 6 → 2 | 284096 → 366528 |
|
||||
| Authored detour/label | 0 → 0 | 0 → 0 | 2348 → 187 | 6 → 0 | 628040 → 83820 |
|
||||
| Fixed ports | 0 → 0 | 0 → 0 | 916 → 863 | 4 → 4 | 125976 → 116754 |
|
||||
| Reversed children in two containers | 148 → 0 | 1 → 0 | 872 → 372 | 4 → 0 | 288512 → 272800 |
|
||||
| Long ordinary labels | 36 → 36 | 2 → 0 | 1340 → 1436 | 4 → 4 | 200448 → 208800 |
|
||||
|
||||
Proper interior crossings, unrelated node overlaps, unrelated edge/node
|
||||
penetrations, label/label collisions, unrelated label/stroke intersections and
|
||||
route warnings are zero in the baseline, reset and candidate outputs. This is
|
||||
not proof of crossing elimination: the crossing definition excludes bend and
|
||||
T contacts, and overlapping strokes can make endpoint pairing ambiguous.
|
||||
|
||||
The parent inspected offline geometry for the reversed-container baseline and
|
||||
candidate, crossed-bipartite candidate and long-label candidate. Reordering the
|
||||
right container's children separates the two routes; the bipartite result has
|
||||
a visually ambiguous shared central trunk. The long-label boxes occupy the
|
||||
available corridors. These images render core boxes/lines, not actual label
|
||||
glyphs or the desktop application, and therefore are not native UI acceptance.
|
||||
|
||||
Every candidate reports exact same-input determinism, idempotence and equality
|
||||
to its first result for calls 2–10. Reported semantic, node identity/metadata and
|
||||
nongeometry conservation hold. JSON and canonical single-source parse/format
|
||||
round trips hold for all nine before/baseline/reset/candidate Projects. The
|
||||
authored-detour route changes intentionally. These assertions do not separately
|
||||
establish hidden-route or attachment lifecycle policy. Other-view conservation
|
||||
is vacuous in these single-view fixtures.
|
||||
|
||||
Existing Layout's Session operation passes one-step Undo/Redo and history
|
||||
checks. The pure candidate function has no integrated command/history evidence.
|
||||
The [source review](probe-review.md) defines remaining metric and fixture gaps.
|
||||
Folded/filtered topology, State/Allocation diagrams, cycles/undirected graphs,
|
||||
large models, multifile sources, application/API admission and native editing
|
||||
remain outside this run. Issue36's multiline State candidate is not in this base.
|
||||
|
||||
An [independent results audit](results-audit-01.md) checked receipt bindings,
|
||||
complete Projects, all 37 image hashes and eight offline images. It independently
|
||||
recomputed both shared-route regressions and confirmed the scoped conclusions.
|
||||
|
||||
## Implications
|
||||
|
||||
Resetting obsolete bends is useful but insufficient. Hierarchy ordering and
|
||||
label clearance have distinct value, with measurable area/length tradeoffs.
|
||||
Increasing a global gap cannot be assumed to fix shared-route ambiguity.
|
||||
Inspect the existing router's candidate scoring and compare complete endpoint
|
||||
join costs, overlap penalties and available lane candidates using the same
|
||||
geometry. Preserve the full quality vector and endpoint/obstacle invariants;
|
||||
reject a change that merely converts overlap into uncounted contacts.
|
||||
|
||||
The [routing inspection](routing-experiment-plan.md) identified a concrete
|
||||
asymmetry: a locally selected route leg scores the source join but omits the
|
||||
target-stub join until after choosing that leg. Test that small correction first,
|
||||
at unchanged node positions, before the auditor's proposed alignment/spacing
|
||||
alternatives. This is a falsifiable source-based hypothesis, not a conclusion
|
||||
that it explains all shared routes. A separate committed candidate will preserve
|
||||
this first control; no overlap weight or node placement should change in that
|
||||
comparison.
|
||||
@@ -0,0 +1,56 @@
|
||||
# #32 first experiment — independent results audit
|
||||
|
||||
Source e7deea7039bcf31675cffbb462cfeb19d62a7e20, production baseline715036e132677dd2bc2fb37ed316d93dc9987aec. Command: `cargo run --locked --offline -p oa-core --example auto_layout_probe`; Windows x86_64-pc-windows-gnullvm/dev. Recorded exit0, failure=null, source inputs unchanged. Independently checked receipt-bound log hashes and equal before/after source inventories. No rerun, compiler, GUI or model helper executed.
|
||||
|
||||
**Conclusion: useful evidence for continued experimentation, not a production winner.** All nine finite fixtures completed; candidate conservation/repeat/roundtrip checks pass. Two shared-run regressions are real, while nested/reversed-container/long-label improvements are also supported. There are no predefined quality thresholds, so exit0 means the probe ran, not that layout quality passed.
|
||||
|
||||
## Verified results
|
||||
|
||||
Exactly one metadata row plus nine fixture rows. Every candidate is supported and valid as recorded, repeats exactly from identical input, equals its second-call result, and remains equal to its first result through calls2–10. Existing Layout likewise has passing repeat/history checks. Every before/after/reset/candidate canonical JSON and single-source roundtrip is recorded exact. Candidate semantic/node-identity/visibility/port-anchor/nongeometry booleans are true on all nine. I independently compared complete output Projects after restoring only diagrams, and checked target layout fields and route attachment fields against input: no difference. Most attachment lists are empty, so this is not broad attachment coverage. Other-view checks are vacuous for single-view fixtures.
|
||||
|
||||
The authored_detour_and_label candidate intentionally has authored_routes_exact=false because its three pins and label override are removed. That is the experimental reset policy, not an unexplained conservation failure. Reset-only already removes the detour; layered must earn its additional complexity elsewhere. Actual Undo/Redo was executed only for existing Command::Layout. Layered is a pure transformer with no command/UI integration or history evidence.
|
||||
|
||||
Values below compare **baseline Layout plus reset-only control → layered candidate**, not the original hand-placed input:
|
||||
|
||||
| Fixture | Shared length | Label/node pairs | Bends | Route length | Drawing area |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| flat_chain_4 | 0 → 0 | 0 → 0 | 0 → 0 | 720 → 246 | 213312 → 150744 |
|
||||
| chain_7_row_wrap | 0 → 0 | 0 → 0 | 8 → 0 | 2560 → 492 | 523584 → 271920 |
|
||||
| diamond | 36 → 82 | 0 → 0 | 8 → 4 | 2200 → 688 | 300576 → 260832 |
|
||||
| crossed_bipartite | 276 → 344 | 0 → 0 | 12 → 4 | 3284 → 688 | 300576 → 165360 |
|
||||
| nested_cross_boundary | 0 → 0 | 1 → 0 | 6 → 2 | 1076 → 364 | 284096 → 366528 |
|
||||
| authored_detour_and_label | 0 → 0 | 0 → 0 | 0 → 0 | 240 → 187 | 90816 → 83820 |
|
||||
| fixed_ports | 0 → 0 | 0 → 0 | 4 → 4 | 916 → 863 | 125976 → 116754 |
|
||||
| two_containers_reversed_children | 148 → 0 | 1 → 0 | 4 → 0 | 872 → 372 | 288512 → 272800 |
|
||||
| long_ordinary_labels | 36 → 36 | 2 → 0 | 4 → 4 | 1340 → 1436 | 200448 → 208800 |
|
||||
|
||||
All these control/candidate outputs report zero strict proper crossings, unrelated-node collisions, unrelated edge/node penetrations, label/label pairs, unrelated label/stroke pairs and routing warnings. Therefore this run provides **no discriminating evidence of proper-crossing reduction**. Zero warnings is not proof of unambiguous independent routes.
|
||||
|
||||
## Independently checked regressions and improvements
|
||||
|
||||
- **diamond:** shared length36→82. Control has two18-unit common terminal runs. Candidate retains those and adds one46-unit horizontal shared run for edge pair0009/000c. Nonterminal shared length0→46; this is not just a terminal-exemption artifact. Bends8→4 and length2200→688 improve, but they partially come with merged routing.
|
||||
- **crossed_bipartite:** shared276→344, nonterminal204→272. Control has four18-unit common-tip runs plus204 horizontal. Candidate has those same72 terminal units, two additional46 horizontal overlaps, and a180-unit vertical overlap between distinct edge pairs0009/000c. Independent axis-interval sums match the emitted values exactly. A more compact drawing and fewer turns do not erase this distinguishability regression.
|
||||
- **nested_cross_boundary:** reported label/node collision1→0 and route length1076→364; area284096→366528 increases about29%. The geometry PNG shows the parent widened to place its children horizontally. This is a real tradeoff, not universal improvement.
|
||||
- **two_containers_reversed_children:** shared148→0, label/node1→0, bends4→0, length872→372 and area288512→272800. The hand-authored alternate child order exists independently; the candidate's straight separated connections support a meaningful ordering improvement over reset-only.
|
||||
- **long_ordinary_labels:** label/node2→0, shared36 unchanged, but length1340→1436 and area200448→208800 grow. This is supported clearance-for-space tradeoff using approximate core rectangles, not native glyph evidence.
|
||||
|
||||
Viewed eight offline PNGs: baseline/candidate diamond, baseline/candidate crossed_bipartite, baseline/candidate nested_cross_boundary, candidate two_containers_reversed_children and candidate long_ordinary_labels. They corroborate route sharing and spacing changes. All37 image identities and their manifest binding to the original output log were checked. Images are schematic rectangles/polylines with fixed scale per fixture, not application renders or text measurements.
|
||||
|
||||
## Method limits versus actual failures
|
||||
|
||||
Proper-crossing definition excludes T contacts and bend intersections; shared length counts pairwise traversal multiplicity. I recomputed the two reported regressions independently from axis-aligned intervals, so those particular increases are actual geometry outcomes, not metric bugs. An unconditional dominance claim fails on those results, but the experiment has not predeclared a total preference ordering across compactness and sharing. Retain the whole metric vector.
|
||||
|
||||
Reset eligibility is post-baseline-Layout versus pre-layout in the candidate; equivalent for current unchanged-visibility fixtures only. No folded/filter/omitted-node/State/Allocation/undirected-cycle/dense scaling/UI admission/multi-file source lifecycle acceptance follows. The source work budget is partial and runtime complexity was not established here. No native GUI, universal label-ink correctness, candidate command Undo, or issue32 completion is claimed. Base715 lacks the separate36 measured State label follow-up.
|
||||
|
||||
## Next falsifiable experiment
|
||||
|
||||
Keep these nine frozen inputs and add one explicit orthogonal proper-crossing witness plus a non-incident overlap/touch counterexample to verify the evaluator distinguishes them. Then isolate diamond/bipartite routing interaction with a tiny predeclared set of node-placement alternatives (current top alignment, centered rank, deterministic stagger, conservative wider gap), keeping the router unchanged. Record actual routed metrics for every alternative; do not silently choose whichever plot looks best or optimize only bend count.
|
||||
|
||||
Hypothesis: a bounded alignment/spacing change can remove the candidate's excess nonterminal sharing without surrendering reversed-container and long-label gains. Falsifier: no alternative reaches control-or-better shared length while retaining no new obstacle/label collisions and predeclared reasonable area/length bounds. Use controls' reported geometry as a fixed comparator and preserve every alternative; if it fails, investigate router channel/parallel-edge handling rather than repeatedly widening all spacing or introducing a whole external engine. This next probe remains diagnostic; attachment/hidden-route sentinels and real command/history/native validation follow before production selection.
|
||||
|
||||
Evidence SHA256:
|
||||
- 01-probe/command/result.json: `119179803e8c26b960ca4280e0429bb537a6f9ff5666267e49bfab989f48dc73`
|
||||
- 01-probe/command/output.log: `21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`
|
||||
- 01-probe/command/inputs-before.json: `2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe`
|
||||
- 01-probe/command/inputs-after.json: `2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe`
|
||||
- geometry/manifest.json: `022fa0f307f9fb92fccbbc139637c62f40d1dcc3a4ea555a35c6b08d82bdb3b5`
|
||||
@@ -0,0 +1,92 @@
|
||||
# Target-join scoring experiment
|
||||
|
||||
**Keep experimental.** Accounting for the target turn during route-leg selection
|
||||
confirms the suspected source/target scoring asymmetry, but does not establish
|
||||
uniform readability improvement. The original bipartite scene becomes more
|
||||
overlapped. Do not integrate this branch as a completed Arrange fix.
|
||||
|
||||
Production routing/test source is `497c1ad8b39788148c5f03bc8542d6d8e28dbc01`.
|
||||
Successor `08656b18bf8934cf264469cf68fc6dea97c15cbb` only resolves three strict
|
||||
Clippy findings in the diagnostic observer. Probe runs at both commits emitted
|
||||
the same 371192 bytes, SHA256
|
||||
`f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
|
||||
The [independent source review](terminal-join-source-review.md) and
|
||||
[independent results audit](terminal-join-results-audit.md) retain the scoped
|
||||
claims and limitations. The latter predates the completed contact audit below.
|
||||
|
||||
The [evidence archive](run-j/terminal-join-08656b18.zip) contains original runs
|
||||
02–06, including the failed Clippy run, source inventories, full Projects and
|
||||
geometry, comparison JSON, independent contact audit/script, runners and 37
|
||||
offline geometry images. It is 3178939 bytes, SHA256
|
||||
`bd2146237353af05b8667dc7bd728007143a2f1b24ad9f8728fdbc50ffb3368e`.
|
||||
[Manifest](run-j/manifest.json) records every member; every archived byte was
|
||||
compared with its original. Paths in original receipts identify the builder's
|
||||
machine, not a dependency on a peer's filesystem.
|
||||
|
||||
## Checks and comparison
|
||||
|
||||
Windows Rust 1.98.1 gnullvm, locked/offline, one job, incremental disabled;
|
||||
Linux excluded. All receipts close with unchanged inputs and no runner failure.
|
||||
|
||||
```text
|
||||
cargo test --locked --offline -p oa-core --lib --test release_routing --test routing_geometry --test routing_labels --test state_diagrams --test group_movement
|
||||
cargo run --locked --offline -p oa-core --example auto_layout_probe
|
||||
cargo clippy --locked --offline -p oa-core --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
Tests: 185 passed, zero failed/ignored (132 library, 7 group movement, 13 release
|
||||
routing, 18 routing geometry, 2 routing labels, 13 State). Three new private tests
|
||||
exercise fast/grid terminal scoring in four orientations, absent continuation,
|
||||
straight/reversal and zero-length legs. Existing authored-pin/attachment/history
|
||||
checks pass. Initial Clippy rejected two manual-range expressions and one nested
|
||||
if in the observer; after that observer-only cleanup, strict core/all-target
|
||||
Clippy passes and the rerun output is byte-identical. No whole-workspace/native
|
||||
acceptance is implied.
|
||||
|
||||
Across all 37 before/baseline/reset/layered/manual-witness variants, complete
|
||||
Projects, projected nodes, projected ports and exact route endpoints are
|
||||
unchanged versus the first experiment. This isolates routing/label placement;
|
||||
it is stronger than merely reusing fixture input. All nine candidate invariants,
|
||||
round trips, deterministic repeats and calls 2–10 remain exact. The candidate
|
||||
still has no integrated command Undo/Redo evidence.
|
||||
|
||||
- Layered diamond: shared length 82→36, nonterminal 46→0; all other original
|
||||
metrics unchanged. Remaining 36 units are common terminal stubs.
|
||||
- Layered bipartite: shared length 344→187, nonterminal 272→115; routed drawing
|
||||
area 165360→175960. Labels, bends, length and other recorded metrics unchanged.
|
||||
Seven other layered metric vectors are unchanged.
|
||||
- **Original bipartite regression:** sharing 730→872, nonterminal 658→800;
|
||||
bends 5→4 and length 2076→2064. The scoring change can favor fewer bends over
|
||||
distinguishable routes. This is not a monotonic quality improvement.
|
||||
- Original diamond sharing 136→36; original two-container sharing 200→54;
|
||||
existing Layout/reset-only two-container sharing 148→18. The independent
|
||||
audit lists the complete changed vector; 30 of 37 variants are unchanged.
|
||||
|
||||
The separate Python contact audit uses orthogonal interval reasoning to
|
||||
reconstruct BOTH old and new contacts. Primitive witnesses pass; all 37 new
|
||||
contact/proper counts match Rust, and all 37 old proper counts match v1. Layered
|
||||
diamond contacts decrease 3→2. Layered bipartite contacts increase 8→9: eight bend
|
||||
contacts become six bend plus three T contacts. Proper crossings remain zero.
|
||||
Thus decreased coincident length partly trades into branch contacts. Details,
|
||||
edge IDs, coordinates and definitions are in the archive's
|
||||
`support/auto-layout-contact-audit-result-20260925.json`; script is adjacent.
|
||||
There is no inferred aggregate quality pass.
|
||||
|
||||
The parent viewed diamond/bipartite offline images: diamond branches separate,
|
||||
but bipartite horizontal tails remain visually joined despite separate vertical
|
||||
channels. These are schematics of core bounds, not native application or glyph
|
||||
evidence. The [residual diagnosis](residual-routing.md) confirms four genuine
|
||||
shared semantic ports; distinct-port placement is not the defect. Of 187 shared
|
||||
units, 72 are bounded common-port stubs and 115 are avoidable interior overlap.
|
||||
|
||||
## Next discriminating comparison
|
||||
|
||||
Retain this J result as a frozen control. Test one predeclared overlap coefficient
|
||||
3.0 instead of 0.12, with the existing per-segment cap 80, crossing cost 24,
|
||||
node/port geometry and edge ordering unchanged. This P variant is an isolated
|
||||
experiment, not a proposed default or a release-ready source change. Preserve
|
||||
the original bipartite regression as a sentinel and the entire quality vector.
|
||||
If stronger penalties cannot choose useful existing alternatives, inspect
|
||||
bounded parallel lane candidates separately; do not silently combine scoring,
|
||||
spacing, caps and ordering changes. A candidate that shifts overlap into hard-to-
|
||||
follow contacts, label collisions or large detours has not solved the user task.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Complete scoring/lane comparison
|
||||
|
||||
**Stop tuning these nine fixtures; retain the variants as experimental evidence.**
|
||||
Bounded parallel lane candidates have some measurable value, but do not resolve
|
||||
the compact bipartite ambiguity and introduce a routing-cost concern. The
|
||||
stronger overlap coefficient is no longer present at the branch tip. No routing
|
||||
or Arrange replacement has been accepted for production.
|
||||
|
||||
PL source `d0be9ff0674373fcf9623daf62bbf50dad02c4df` combines target-join J,
|
||||
coefficient 3.0/cap 80 and bounded lanes. L source
|
||||
`e8ec6dbb3160f62476a5557f14605f68959f65fe` restores coefficient 0.12, retaining
|
||||
J and lanes. Each leg keeps every obstacle coordinate and adds at most 64
|
||||
deterministic coordinates per axis at CLEARANCE offsets from settled other-edge
|
||||
segments. Fast/grid searches receive the same augmented space. Endpoint geometry,
|
||||
authored pins, attachments and model metadata are not edited by this operation.
|
||||
|
||||
The [source review](lanes-source-review.md) records attribution limits: retained
|
||||
coordinates are bounded, but collection/sorting of prior segments is not charged
|
||||
to the search budget. Extra axes can hit the existing grid-cell cap and can alter
|
||||
grid scores through segment subdivision. This is not a proof of globally optimal
|
||||
paths or constant preparation cost. No new engine/runtime dependency was added.
|
||||
|
||||
## Results
|
||||
|
||||
Every one of the 37 complete Projects, node sets, port sets and exact endpoints
|
||||
matches its control in both comparisons. All nine candidate invariants,
|
||||
roundtrips and repeated-call checks hold. Values below are raw pairwise shared
|
||||
length for the crossed-bipartite fixture; complete vectors remain in the archive.
|
||||
|
||||
| Router | Original scene | Existing Layout/reset | Layered candidate |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Released router | 730 | 276 | 344 |
|
||||
| J | 872 | 276 | 187 |
|
||||
| J + stronger penalty (P) | 730 | 276 | 187 |
|
||||
| J + stronger penalty + lanes (PL) | 724 | 72 | 176 |
|
||||
| J + lanes, original penalty (L) | 724 | 276 | 176 |
|
||||
|
||||
PL's existing-Layout/reset result eliminates 204 nonterminal shared units but
|
||||
adds one proper crossing, 24 route-length units and 19392 area units. Contacts
|
||||
decrease 6→5; these tradeoffs stay explicit. L with the original coefficient
|
||||
does not achieve that baseline improvement. Both lane variants leave 104
|
||||
nonterminal units in the compact layered case, with nine point contacts. Its
|
||||
drawing area returns from J's 175960 to 165360. Eight other layered metric
|
||||
vectors are unchanged. The parent viewed the PL bipartite schematic: vertical
|
||||
channels are separated, but horizontal tails still join at ambiguous branches.
|
||||
|
||||
Compared with J, L reduces original bipartite sharing 872→724 and original
|
||||
two-container sharing 54→12 without changing the other original quality fields;
|
||||
two-container baseline/reset sharing reduces 18→12. PL compared with P includes
|
||||
a two-container original sharing regression 6→12 while reducing one bend, 12
|
||||
length units and one contact. The [PL audit](penalty-lanes-audit.md) documents all
|
||||
seven changed rows; no scalar is treated as a universal quality score. Labels,
|
||||
obstacles and warnings remain separately checked. Core schematics and approximate
|
||||
label boxes do not establish actual glyph layout or native route traceability.
|
||||
|
||||
## Verification and evidence
|
||||
|
||||
Same frozen Windows Rust1.98.1 gnullvm environment, one Cargo job, locked/offline,
|
||||
incremental disabled. Linux excluded. All runs close with exit0, unchanged
|
||||
inputs and no runner failure:
|
||||
|
||||
```text
|
||||
# PL: five matched tests, including all three new lane tests
|
||||
cargo test --locked --offline -p oa-core --lib lane
|
||||
# L: 188 tests passed, zero failed/ignored
|
||||
cargo test --locked --offline -p oa-core --lib --test release_routing --test routing_geometry --test routing_labels --test state_diagrams --test group_movement
|
||||
# Both variants: complete nine-fixture diagnostic
|
||||
cargo run --locked --offline -p oa-core --example auto_layout_probe
|
||||
# L: strict core/all-target Clippy passed
|
||||
cargo clippy --locked --offline -p oa-core --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
The full 188 check is for L, not PL: an existing private J test intentionally
|
||||
asserts the original 0.12 cost. PL's filtered run executes three new lane tests
|
||||
and two existing Scenario tests matched by `lane`; 130 other library tests are
|
||||
filtered. Lane witnesses cover base-coordinate preservation, 64-extra bounds,
|
||||
deduplication/order independence, relevance ranking, nonfinite rejection and
|
||||
fast/grid selection of a feasible parallel path under the experimental cost.
|
||||
|
||||
**Cost signal:** routing_geometry's 18-test runtime is 16.43s under L versus
|
||||
4.30s under J on the same machine/environment. This excludes compilation, but
|
||||
is one suite observation per variant, not an isolated route benchmark or a
|
||||
performance bound. It warrants profiling before adopting per-leg lane scans.
|
||||
Whole cargo/probe elapsed times include compilation and are unsuitable for that
|
||||
comparison.
|
||||
|
||||
The [independent final L/four-way audit](lanes-results-audit.md) confirms all 37
|
||||
fixed bindings and the 188-test result, checks the recorded geometry/contact
|
||||
evidence, and likewise recommends withholding L from production pending the
|
||||
independent corpus and route-only timing.
|
||||
|
||||
[Evidence archive](run-lanes/lanes-e8ec6db.zip), 3518507 bytes, SHA256
|
||||
`5512b4cbd99e3bf03eb975e25fb980f7b1a95a5cb19f3687fb3d6d83d1839e8f`,
|
||||
contains original runs08–12, 74 offline images, complete comparisons, independent
|
||||
axis-based contact audits, binary identities and runners. [Manifest](
|
||||
run-lanes/manifest.json) binds every member, all byte-compared to originals.
|
||||
PL output SHA256 `04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd`;
|
||||
L output SHA256 `64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d`.
|
||||
The earlier P result and original archive remain linked in [results-p.md](results-p.md).
|
||||
|
||||
## Decision and next evidence
|
||||
|
||||
Do not choose a global router policy from these nine scenes. Freeze a small
|
||||
independent corpus before the next run: realistic authored nested/folded content,
|
||||
mixed-direction shared/distinct-port fan-in/out with a fixed edge-ID permutation,
|
||||
and a modest sparse diagram for isolated routing-time/budget observations. Compare
|
||||
J and L with an explicit route-tracing rubric and full quality vector. Preserve
|
||||
the original Scene/Arrange distinction and source/history lifecycle constraints.
|
||||
This should decide whether the lane cost is justified or the simpler router
|
||||
should be retained before broadening the Layout prototype. Fold/filter rules,
|
||||
one-command Undo, API/source parity and real desktop acceptance remain required;
|
||||
the separately pending State-label issue36 is not silently included here.
|
||||
@@ -0,0 +1,50 @@
|
||||
# Capped overlap-penalty experiment
|
||||
|
||||
**P alone does not solve the arranged bipartite overlap.** Source
|
||||
`3d7adff923dee5bed54dfdccc119dbee0c7c2773` changes only the overlap coefficient
|
||||
from 0.12 to 3.0 (plus an experiment comment), retaining the per-segment cap 80.
|
||||
Node placement, ports, target-join J logic, edge order and crossing cost remain
|
||||
unchanged. This is a transient diagnostic source variant, not a proposed default.
|
||||
|
||||
Windows command `cargo run --locked --offline -p oa-core --example
|
||||
auto_layout_probe` completed exit 0 with unchanged inputs at
|
||||
2026-09-25T01:04:57Z. Same frozen Rust1.98.1 gnullvm environment as J; Linux
|
||||
excluded. Output SHA256
|
||||
`13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
|
||||
J's 185 passing tests and strict Clippy are not claimed for P; this run executes
|
||||
the diagnostic observer and its analytic primitives only.
|
||||
|
||||
[Original evidence archive](run-p/penalty-3d7adff.zip), 916568 bytes, SHA256
|
||||
`6b819b01c8012aa72d423443f4dc04ae261f1ee9dc6907f0063c219ff173ad36`,
|
||||
contains receipts, complete Projects/geometry, independent contact audit,
|
||||
comparison, renderer output and runner. [Manifest](run-p/manifest.json) binds
|
||||
original bytes and post-run probe executable; every member was checked against
|
||||
its local original.
|
||||
|
||||
Complete Projects, nodes, ports and route endpoints are exact versus J in all
|
||||
37 variants. All nine layered candidates retain the previous quality vector;
|
||||
in particular bipartite sharing remains 187 (115 nonterminal), with nine contacts
|
||||
and zero proper crossings. Two original-scene vectors change; the other 35 do
|
||||
not:
|
||||
|
||||
| Original scene | Shared length J → P | Bends | Route length | Point contacts |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| Crossed bipartite | 872 → 730 | 4 → 5 | 2064 → 2076 | 9 → 10 |
|
||||
| Reversed children in two containers | 54 → 6 | 4 → 5 | 1512 → 1524 | 2 → 3 |
|
||||
|
||||
The bipartite result restores the first experiment's original-scene vector;
|
||||
the extra bend/length tradeoff was predicted by the low overlap cost diagnosis.
|
||||
Both contact increases remain visible rather than being counted as a clean
|
||||
readability win. These results concern core geometry, not native route tracing.
|
||||
|
||||
The [independent P audit](penalty-results-audit.md) confirms these results and
|
||||
all nine recorded conservation/roundtrip/repetition checks. Both additional
|
||||
point contacts are T contacts; no proper crossing change is hidden by the table.
|
||||
|
||||
The next L comparison adds a bounded number of deterministic parallel lane
|
||||
coordinates while preserving all existing obstacle coordinates and fixed
|
||||
endpoints. Use the same augmented geometry for fast/grid search. P+L and J+L
|
||||
will distinguish available alternatives from preference. The cap 80 may still
|
||||
reject a four-turn detour whose extra length/turn cost exceeds it; retain that
|
||||
outcome rather than retuning cap, ordering and spacing together. No weight or
|
||||
lane policy is accepted for production by this diagnostic run.
|
||||
@@ -0,0 +1,53 @@
|
||||
# #32 next routing experiment: distinguish shared terminals from ambiguous trunks
|
||||
|
||||
Local source/receipt diagnosis only; no builds, formatters, GUI or product edits. Input: completed `e7deea70` probe `.local/auto-layout-checks-20260925/01-probe/command/output.log`; implementation read from `.local/auto-layout-20260925/crates/oa-core/src/routing.rs`. The probe uses **core estimated label bounds**, not renderer glyph measurement. No new candidate module is justified until the required private routing hook is agreed.
|
||||
|
||||
## Exact observed geometry
|
||||
|
||||
The layered diamond has 82 units of pairwise shared length: 36 classified as common terminal stubs, 46 nonterminal. Edges ending `009` and `00c` share the physical output `(264,106)`, its 18-unit stub to `(282,106)`, then an avoidable extra horizontal run to `(328,106)`. Edge `00c` then turns down to `(328,286)` and enters `(346,286)`. A candidate branching immediately at `(282,106)`, going to `(282,286)`, then right to the target would separate that extra 46-unit trunk while preserving the port and stub. This is a geometric proposal, not a verified collision-free final result; the same obstacle and label checks must evaluate it.
|
||||
|
||||
The layered crossed-bipartite case has 344 shared units: 72 common-terminal, 272 nonterminal. Its opposite diagonal routes both use `x=328, y=106..286`, an exact 180-unit coincident vertical run. Top and bottom horizontal portions add 92 nonterminal shared units. The source stubs are at `x=282`; target stubs at `x=328`. Proper crossings are reported as zero, but these coincident routes do not provide unambiguous independent traces. Do not treat the zero as a solved crossing problem.
|
||||
|
||||
## Source evidence: a local scoring asymmetry precedes penalty tuning
|
||||
|
||||
`crossing_cost` charges `min(shared_length * 0.12, 80)` per previously occupied segment, multiplied by segment count. A proper interior crossing costs24. `BEND_COST` is24. `RoutingSpace::new` uses obstacle boundary coordinates; fast-path candidates add the start/end midpoint, and grid coordinates add start/end. Neither systematically adds lanes offset from previously occupied trunks.
|
||||
|
||||
More importantly, `fast_path(start, end, space, previous, incoming)` includes the turn from the preceding source-side segment, but has no outgoing direction parameter. `route_edge` chooses this local path and only later appends the final target attachment point `b.point`; complete `path_cost` is then compared across endpoint choices, not across the discarded alternative paths for that same endpoint pair. With fixed semantic ports there may be no alternate endpoint choice to recover the discarded route. `grid_path` is only a fallback when `fast_path` returns None, not a better-cost search after a valid fast path.
|
||||
|
||||
For the diamond, horizontal-then-vertical has one internal bend and no incoming bend; its 46-unit shared portion costs5.52. Vertical-then-horizontal has one internal bend plus an incoming bend, costing24 extra locally. But appending the target segment adds the missing final bend to horizontal-then-vertical. Complete paths have equal bend counts; the local comparison prefers the shared route because it omitted one terminal join. The 180-unit bipartite overlap costs21.6, also below one turn. This explains a plausible bias, not proof that correcting it resolves every route.
|
||||
|
||||
## Minimal discriminating comparison (proposal to parent)
|
||||
|
||||
Freeze layered node positions, labels' text, attachments, port identities/anchors, edge order and work budgets. Compare a small fixed sequence, not an open parameter search:
|
||||
|
||||
1. **J: symmetric terminal-join cost.** Supply an optional outgoing point/direction to fast-path scoring. For the final segment to `b.stub`, use `b.point`; include `turn_cost(penultimate, end, outgoing)` both in actual candidate score and admissible pruning estimates where applicable. Intermediate authored pins have no predetermined outgoing direction; do not invent one. If grid routing supports this experiment too, target state selection must account for the terminal turn before returning the best result. Preserve baseline behavior for absent outgoing context. This isolates the suspected bias without stronger penalties or enlarged diagrams.
|
||||
2. **JP: J plus stronger shared-run penalty.** One declared test coefficient, e.g.1.0 per unit with the existing80 cap, compared with0.12. Keep the proper crossing cost24 unchanged so the comparison exposes whether penalizing overlap merely substitutes crossings. Do not choose this variant solely by shared length. Preserve all hard endpoint constraints.
|
||||
3. **JPL: JP plus bounded lane candidates.** For occupied horizontal/vertical trunks, offer parallel offsets of `CLEARANCE` on either side where applicable; validate obstacle clearance and fixed terminal stubs. Use a strict deterministic global cap on added coordinates/candidates and reuse existing work exhaustion handling. This tests whether absent geometric alternatives, rather than insufficient penalty, is the blocker. No persisted waypoint authoring and no unconstrained port movement.
|
||||
4. **Spacing control.** Only if J/JP fail, compare the unchanged router with one fixed additional inter-layer gap (e.g.24 world units). This is a control, not the assumed remedy: larger gaps may lengthen shared trunks and enlarge diagrams while retaining identical topological ambiguity. Do not mix spacing and router changes in the first comparison.
|
||||
|
||||
The first J variant is the smallest informative next experiment. If it removes diamond's extra trunk while retaining invariants, stop and inspect results before implementing JP/JPL. A clean shared terminal fan-out need not eliminate its unavoidable initial18-unit stub. Conversely, sharing a node identity does not exempt arbitrary later overlap, and different physical ports on the same node must not be collapsed into one endpoint exemption.
|
||||
|
||||
## Required hook and ownership boundary
|
||||
|
||||
The candidate module can call public `route_diagram`, but cannot change private `crossing_cost`, `fast_path`, `grid_path` or candidate generation. Returning a changed Project with temporary authored waypoints would test a different policy and would violate the generated-elbows-remain-derived experiment. Copying the entire router into an example introduces unnecessary divergence.
|
||||
|
||||
Therefore propose a parent-owned isolated routing experiment hook, with no default production behavior change, or a separate disposable source variant controlled by the existing runner. Evaluator needs an optional routing provider returning `RoutedView` for a fixed Project, rather than only `candidate -> Project`. It must reuse that provider for every metric, capture, and repeat check and label the variant explicitly. Until parent approves that hook, no module/interface changes were made. The current original/reset/layered comparisons remain reproducible.
|
||||
|
||||
## Falsifiers and risks
|
||||
|
||||
Evaluate both raw and terminal-excluded shared length, proper crossings, T/bend contacts, route lengths/turns, unrelated-node/header penetration, label collisions, warnings and runtime/work counts. A positive overlap moved onto a bend is not a successful reduction in intersections. The crossed K2,2 fixture with fixed port ordering may require a genuine visible crossing or an outer detour; do not demand zero overlap AND zero crossings without a fixed-attachment feasible witness. Separate forced terminal contacts from independently traceable route interiors.
|
||||
|
||||
Keep diamond, crossed-bipartite, chain and long-label fixtures; add a fixed shared-output fan-out, two distinct ports on one node, opposite-direction connections, and a narrow obstacle corridor. Verify exact endpoint coordinates and metadata; preserve ordinary authored pins and preview/settled agreement if the routing change advances beyond this isolated experiment. Stable-ID order can privilege earlier routes, so rerun the same graph under a fixed edge-ID permutation and disclose sensitivity instead of relabeling edges to improve the score.
|
||||
|
||||
Labels are placed after paths settle; lane changes can worsen label collisions even when node positions stay fixed. Parent's eventual GUI inspection should trace each diagonal from its source label/port through the corridor to its intended target at normal zoom. No geometry metric alone establishes that user outcome. This note selects a falsifiable experiment, not an accepted product fix.
|
||||
|
||||
## Exact J patch plan, held for parent's separate candidate pin
|
||||
|
||||
No edits to `routing.rs` are authorized yet. After parent publishes the first experiment evidence, the narrowly proposed change is:
|
||||
|
||||
- Add `outgoing: Option<Position>` beside `incoming` in private `fast_path` and `grid_path` only. At `route_edge`'s loop over authored pins followed by `b.stub`, pass `Some(b.point)` only when `index == pins.len()`; pass `None` for every intermediate waypoint. The preceding settled path still supplies `incoming` exactly as now. No public API or metadata change.
|
||||
- In `fast_path`, extend its shared `join(path)` closure with the terminal turn from `path[path.len()-2]` through `end` to `outgoing`, when two path points exist. Both `estimate(path)` and actual scoring already call `join`; change both consistently through that closure. Keep the two-bend lower-bound early exit: Manhattan distance plus two bend costs remains a lower bound for two-bend alternatives because terminal penalties are nonnegative. Keep final whole-path `path_cost` unchanged; local scoring does not persist a cost, so it does not double-charge the returned path.
|
||||
- In `grid_path`, add the terminal turn **during relaxation when `next == last`**, using `turn_cost(a, b, outgoing)`. Include it in `costs[state]` and the queue priority before the target state can be popped. Do not merely add a penalty after returning the first reached target: that would fail to compare alternative arrival directions. The existing Manhattan heuristic remains admissible because the new terminal penalty is nonnegative. The initial incoming-turn logic remains unchanged.
|
||||
- `start == end` has no locally selectable segment. Keep the degenerate result, and rely on whole-path scoring for the junction between preceding/following points. Do not fabricate a direction from an absent penultimate point. Waypoint positions/order remain exact; this patch does not claim globally optimal look-ahead across several hard-pin legs.
|
||||
|
||||
Focused tests before comparing full fixtures: (1) fast-path diamond geometry with one occupied horizontal trunk, fixed start/target stubs, asserting the equal-complete-bend alternative branches earlier; (2) directly exercise grid routing with two clear arrivals where adding the target join changes the preferred total, compare complete cost to an enumerated feasible alternative; (3) mirrored/rotated terminal geometry, including straight continuation and reversal costs; (4) outgoing=None preserves established intermediate-waypoint behavior; (5) full route with one/multiple authored pins retains exact pins and terminal attachments, plus start=end leg; (6) preview versus settled geometry remains consistent under the same baseline/budget. Use private unit tests for fast/grid so a passing public route cannot accidentally avoid the grid test. Then rerun the unchanged probe corpus and report the complete quality vector, especially any newly visible crossings. No expected overall improvement is asserted before execution.
|
||||
@@ -0,0 +1 @@
|
||||
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
|
||||
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"source_commit": "e7deea7039bcf31675cffbb462cfeb19d62a7e20",
|
||||
"baseline_commit": "715036e132677dd2bc2fb37ed316d93dc9987aec",
|
||||
"scope": "Nine small SA FunctionalDataflow diagnostic fixtures; Windows core geometry, not native UI or production acceptance.",
|
||||
"binary_after_completed_run": {
|
||||
"path": "target/debug/examples/auto_layout_probe.exe",
|
||||
"bytes": 24039424,
|
||||
"sha256": "a95736170f58d25c60a16f2683b961aad8b31f97e4357c3e0d2f7e81d21176bd"
|
||||
},
|
||||
"members": {
|
||||
"run/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"run/command/context.json": {
|
||||
"bytes": 3488,
|
||||
"sha256": "4dd4e602c2b33fd229a7241e1a4d6a2de399df197b5613af4b3126bfd357c476"
|
||||
},
|
||||
"run/command/inputs-after.json": {
|
||||
"bytes": 1722092,
|
||||
"sha256": "2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe"
|
||||
},
|
||||
"run/command/inputs-before.json": {
|
||||
"bytes": 1722092,
|
||||
"sha256": "2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe"
|
||||
},
|
||||
"run/command/output.log": {
|
||||
"bytes": 331975,
|
||||
"sha256": "21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1"
|
||||
},
|
||||
"run/command/result.json": {
|
||||
"bytes": 4124,
|
||||
"sha256": "119179803e8c26b960ca4280e0429bb537a6f9ff5666267e49bfab989f48dc73"
|
||||
},
|
||||
"run/command/stderr.log": {
|
||||
"bytes": 279,
|
||||
"sha256": "492e4346b5daf9d9eed2aa96c89c5104b9d8d7f830074b1346c9f5aaf053d662"
|
||||
},
|
||||
"run/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"run/orchestration.log": {
|
||||
"bytes": 165,
|
||||
"sha256": "e4bf56f792c8e8fc9288fc08ef5f0159941b8026e435a427722b59ccc4e34831"
|
||||
},
|
||||
"geometry/authored_detour_and_label-after.png": {
|
||||
"bytes": 12492,
|
||||
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
|
||||
},
|
||||
"geometry/authored_detour_and_label-before.png": {
|
||||
"bytes": 12468,
|
||||
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
|
||||
},
|
||||
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
|
||||
"bytes": 13162,
|
||||
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
|
||||
},
|
||||
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
|
||||
"bytes": 12777,
|
||||
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-after.png": {
|
||||
"bytes": 14271,
|
||||
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-before.png": {
|
||||
"bytes": 13771,
|
||||
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
|
||||
"bytes": 14396,
|
||||
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
|
||||
"bytes": 14549,
|
||||
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
|
||||
},
|
||||
"geometry/crossed_bipartite-after.png": {
|
||||
"bytes": 13144,
|
||||
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
|
||||
},
|
||||
"geometry/crossed_bipartite-before.png": {
|
||||
"bytes": 13413,
|
||||
"sha256": "8622726dfdfc01e93fcd2d9d22c6d082e5a169b9dcd59f788e876954431214fd"
|
||||
},
|
||||
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
|
||||
"bytes": 13848,
|
||||
"sha256": "de238d7e904a050b93cc63926f9b4b4723d4b98e6741971fc98f81d771a8a52e"
|
||||
},
|
||||
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
|
||||
"bytes": 13349,
|
||||
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
|
||||
},
|
||||
"geometry/diamond-after.png": {
|
||||
"bytes": 12556,
|
||||
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
|
||||
},
|
||||
"geometry/diamond-before.png": {
|
||||
"bytes": 13255,
|
||||
"sha256": "30d514155ec0e88a68e62089cd50b7747924a81095c957aa67b1bf5a70ac18f8"
|
||||
},
|
||||
"geometry/diamond-experimental_candidate-metrics.png": {
|
||||
"bytes": 13581,
|
||||
"sha256": "14dc1304822e74f8c7e0146a02af69ea39dc90d0d655a75b97383644c04b8900"
|
||||
},
|
||||
"geometry/diamond-reset_only_control-metrics.png": {
|
||||
"bytes": 12982,
|
||||
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
|
||||
},
|
||||
"geometry/fixed_ports-after.png": {
|
||||
"bytes": 11889,
|
||||
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
|
||||
},
|
||||
"geometry/fixed_ports-before.png": {
|
||||
"bytes": 12013,
|
||||
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
|
||||
},
|
||||
"geometry/fixed_ports-experimental_candidate-metrics.png": {
|
||||
"bytes": 12394,
|
||||
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
|
||||
},
|
||||
"geometry/fixed_ports-reset_only_control-metrics.png": {
|
||||
"bytes": 12231,
|
||||
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
|
||||
},
|
||||
"geometry/flat_chain_4-after.png": {
|
||||
"bytes": 12582,
|
||||
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
|
||||
},
|
||||
"geometry/flat_chain_4-before.png": {
|
||||
"bytes": 12723,
|
||||
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
|
||||
},
|
||||
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
|
||||
"bytes": 13405,
|
||||
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
|
||||
},
|
||||
"geometry/flat_chain_4-reset_only_control-metrics.png": {
|
||||
"bytes": 12918,
|
||||
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
|
||||
},
|
||||
"geometry/long_ordinary_labels-after.png": {
|
||||
"bytes": 12643,
|
||||
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
|
||||
},
|
||||
"geometry/long_ordinary_labels-before.png": {
|
||||
"bytes": 12661,
|
||||
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
|
||||
},
|
||||
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
|
||||
"bytes": 13235,
|
||||
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
|
||||
},
|
||||
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
|
||||
"bytes": 12969,
|
||||
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
|
||||
},
|
||||
"geometry/manifest.json": {
|
||||
"bytes": 8099,
|
||||
"sha256": "022fa0f307f9fb92fccbbc139637c62f40d1dcc3a4ea555a35c6b08d82bdb3b5"
|
||||
},
|
||||
"geometry/nested_cross_boundary-after.png": {
|
||||
"bytes": 13344,
|
||||
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
|
||||
},
|
||||
"geometry/nested_cross_boundary-before.png": {
|
||||
"bytes": 13547,
|
||||
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
|
||||
},
|
||||
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
|
||||
"bytes": 13535,
|
||||
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
|
||||
},
|
||||
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
|
||||
"bytes": 13549,
|
||||
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-after.png": {
|
||||
"bytes": 13950,
|
||||
"sha256": "1536fa9da0fa89a64b12e7faf6d0dab1c3fa0177517e39fd1adaeaee3f2214fe"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-before.png": {
|
||||
"bytes": 14076,
|
||||
"sha256": "2f3a2d55d30ff206d9daf9b8f84ba0e960332a02275289c66ab2e104da2e890e"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
|
||||
"bytes": 14500,
|
||||
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
|
||||
"bytes": 14531,
|
||||
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
|
||||
"bytes": 14126,
|
||||
"sha256": "2483bf404953ce9b3da38f2adca10c4e02e34638e2999acae7beecb5fe936a83"
|
||||
},
|
||||
"tooling/run-auto-layout-check-20260925.py": {
|
||||
"bytes": 2771,
|
||||
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
|
||||
},
|
||||
"tooling/run.py": {
|
||||
"bytes": 13814,
|
||||
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
|
||||
},
|
||||
"tooling/auto-layout-format-precommit-20260925.json": {
|
||||
"bytes": 364,
|
||||
"sha256": "29c93825b415e04204d3fe23a85eef0798560bbb5a1a169689326602f65a9f35"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"name": "probe-e7deea70.zip",
|
||||
"bytes": 900995,
|
||||
"sha256": "c52f82d4782cd6a7f8cbe67498c8b2371e99204a65976aa8bcbbd0a86f835069"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
|
||||
@@ -0,0 +1,398 @@
|
||||
{
|
||||
"scope": "Target-join candidate experiment, not production or native acceptance",
|
||||
"runs": [
|
||||
{
|
||||
"run": "02-terminal-join-tests",
|
||||
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"run": "03-terminal-join-probe",
|
||||
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"run": "04-terminal-join-clippy",
|
||||
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
|
||||
"exit_code": 101
|
||||
},
|
||||
{
|
||||
"run": "05-terminal-join-clippy",
|
||||
"source_commit": "08656b18bf8934cf264469cf68fc6dea97c15cbb",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"run": "06-terminal-join-probe",
|
||||
"source_commit": "08656b18bf8934cf264469cf68fc6dea97c15cbb",
|
||||
"exit_code": 0
|
||||
}
|
||||
],
|
||||
"observer_lint_cleanup_output_byte_identical": true,
|
||||
"post_run_probe_binary": {
|
||||
"bytes": 24156160,
|
||||
"sha256": "3541618adc25d12ca136941e973f506cc11bc556840193023d4295c27be758a5"
|
||||
},
|
||||
"members": {
|
||||
"02-terminal-join-tests/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"02-terminal-join-tests/command/context.json": {
|
||||
"bytes": 3658,
|
||||
"sha256": "6d8d90920415df092df40afb4031fdbd12d2bc87a0daebea692b9f9288804783"
|
||||
},
|
||||
"02-terminal-join-tests/command/inputs-after.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
|
||||
},
|
||||
"02-terminal-join-tests/command/inputs-before.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
|
||||
},
|
||||
"02-terminal-join-tests/command/output.log": {
|
||||
"bytes": 18709,
|
||||
"sha256": "f024aaba0fcb680d02d49b5afde398453cf5183a08b561ff96e4c9a42cf70a17"
|
||||
},
|
||||
"02-terminal-join-tests/command/result.json": {
|
||||
"bytes": 4321,
|
||||
"sha256": "4b56d6ac30cc87ba7c7757906a3d0258e056178528b56c77312bd9675ce579f3"
|
||||
},
|
||||
"02-terminal-join-tests/command/stderr.log": {
|
||||
"bytes": 990,
|
||||
"sha256": "73f8f63d3339affe4bf6b47408a2ed020aca62606dc14faa03be3f094550eccf"
|
||||
},
|
||||
"02-terminal-join-tests/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"02-terminal-join-tests/orchestration.log": {
|
||||
"bytes": 179,
|
||||
"sha256": "3c673d3e29089ce517cd6026946443f9ae8fcba2fccb384835fffe2e8e19b58d"
|
||||
},
|
||||
"03-terminal-join-probe/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"03-terminal-join-probe/command/context.json": {
|
||||
"bytes": 3502,
|
||||
"sha256": "380e3e8fae97e1ee75417c1efc3ee64bdca1958aa61caa1766fba86a6c7e52d3"
|
||||
},
|
||||
"03-terminal-join-probe/command/inputs-after.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
|
||||
},
|
||||
"03-terminal-join-probe/command/inputs-before.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
|
||||
},
|
||||
"03-terminal-join-probe/command/output.log": {
|
||||
"bytes": 371192,
|
||||
"sha256": "f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f"
|
||||
},
|
||||
"03-terminal-join-probe/command/result.json": {
|
||||
"bytes": 4166,
|
||||
"sha256": "57a1f866b2cb67880decd26becf3ac2e7715e38bbd26d3089c47dd62294afa4f"
|
||||
},
|
||||
"03-terminal-join-probe/command/stderr.log": {
|
||||
"bytes": 278,
|
||||
"sha256": "686a3d705aa21b73652e7589b1fa44094bbbc05f3118b2886161e0f815c8a334"
|
||||
},
|
||||
"03-terminal-join-probe/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"03-terminal-join-probe/orchestration.log": {
|
||||
"bytes": 179,
|
||||
"sha256": "bf0516c97a7f3003b29a549f463458f3dc5516b1f41af024e9cf7f6062b9280b"
|
||||
},
|
||||
"04-terminal-join-clippy/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"04-terminal-join-clippy/command/context.json": {
|
||||
"bytes": 3521,
|
||||
"sha256": "9f20479acb398ab0dc3c35708ddaef39e4457fcc22f910e13342163718d61fc0"
|
||||
},
|
||||
"04-terminal-join-clippy/command/inputs-after.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
|
||||
},
|
||||
"04-terminal-join-clippy/command/inputs-before.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
|
||||
},
|
||||
"04-terminal-join-clippy/command/output.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"04-terminal-join-clippy/command/result.json": {
|
||||
"bytes": 4185,
|
||||
"sha256": "fe9e21a9e203fa0ecfeed957041faa22180287a2ecd158f8a7e77b881ccffc1b"
|
||||
},
|
||||
"04-terminal-join-clippy/command/stderr.log": {
|
||||
"bytes": 2728,
|
||||
"sha256": "e375843af8e5bb8e921e78b7e7fca844787d6785710506f5e2c5c8b6788beb59"
|
||||
},
|
||||
"04-terminal-join-clippy/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"04-terminal-join-clippy/orchestration.log": {
|
||||
"bytes": 182,
|
||||
"sha256": "949915299dd53b9c59b5116da6f163973cc339d5ae3eb3b1a73151065f68bd6e"
|
||||
},
|
||||
"05-terminal-join-clippy/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"05-terminal-join-clippy/command/context.json": {
|
||||
"bytes": 3521,
|
||||
"sha256": "15bd08c0a37dc3e01a0d046b6cd1341aa11bfc858b8da92ad20512e8401e8815"
|
||||
},
|
||||
"05-terminal-join-clippy/command/inputs-after.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
|
||||
},
|
||||
"05-terminal-join-clippy/command/inputs-before.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
|
||||
},
|
||||
"05-terminal-join-clippy/command/output.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"05-terminal-join-clippy/command/result.json": {
|
||||
"bytes": 4182,
|
||||
"sha256": "6970eff6a4d9741e27acdb2ef2bfceefcd122c1590741edeb7a112f4f5c357d4"
|
||||
},
|
||||
"05-terminal-join-clippy/command/stderr.log": {
|
||||
"bytes": 177,
|
||||
"sha256": "5be2ed4d5b119d9b42e2b1e874e3c9e2d6b27cc0610c7d2300760f51a3dccdbe"
|
||||
},
|
||||
"05-terminal-join-clippy/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"05-terminal-join-clippy/orchestration.log": {
|
||||
"bytes": 180,
|
||||
"sha256": "dc27f63c6f1e1ea3c1e6ff6dac85cf49d5927f6784ee768c3c12b1e8ec62848f"
|
||||
},
|
||||
"06-terminal-join-probe/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"06-terminal-join-probe/command/context.json": {
|
||||
"bytes": 3502,
|
||||
"sha256": "5500c31ead4f64132a628646a9863f587e59ef8281a74a70fcff9a038c283200"
|
||||
},
|
||||
"06-terminal-join-probe/command/inputs-after.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
|
||||
},
|
||||
"06-terminal-join-probe/command/inputs-before.json": {
|
||||
"bytes": 1725008,
|
||||
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
|
||||
},
|
||||
"06-terminal-join-probe/command/output.log": {
|
||||
"bytes": 371192,
|
||||
"sha256": "f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f"
|
||||
},
|
||||
"06-terminal-join-probe/command/result.json": {
|
||||
"bytes": 4166,
|
||||
"sha256": "bd3b20390a03ed7c637586119e12e0e55949303f9b17f6e018f231b1a9095833"
|
||||
},
|
||||
"06-terminal-join-probe/command/stderr.log": {
|
||||
"bytes": 278,
|
||||
"sha256": "8a49d76b8cf56f31f6877cb6baf9d9f82d5abfbc1bfcc2ae73b8d3ff209c482c"
|
||||
},
|
||||
"06-terminal-join-probe/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"06-terminal-join-probe/orchestration.log": {
|
||||
"bytes": 179,
|
||||
"sha256": "e85db49cd4d73dbff0b45f92cfb96016f743db3e64878ceeee078515e7fe324d"
|
||||
},
|
||||
"geometry/authored_detour_and_label-after.png": {
|
||||
"bytes": 12492,
|
||||
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
|
||||
},
|
||||
"geometry/authored_detour_and_label-before.png": {
|
||||
"bytes": 12468,
|
||||
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
|
||||
},
|
||||
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
|
||||
"bytes": 13162,
|
||||
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
|
||||
},
|
||||
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
|
||||
"bytes": 12777,
|
||||
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-after.png": {
|
||||
"bytes": 14271,
|
||||
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-before.png": {
|
||||
"bytes": 13771,
|
||||
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
|
||||
"bytes": 14396,
|
||||
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
|
||||
"bytes": 14549,
|
||||
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
|
||||
},
|
||||
"geometry/crossed_bipartite-after.png": {
|
||||
"bytes": 13144,
|
||||
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
|
||||
},
|
||||
"geometry/crossed_bipartite-before.png": {
|
||||
"bytes": 13406,
|
||||
"sha256": "aa3ba4f8ab67f6cd63d1c31fe309786e139db78ec6a36a0b00e8a854b590fe0c"
|
||||
},
|
||||
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
|
||||
"bytes": 13855,
|
||||
"sha256": "e3cc0a326a2c8b577e40101c5f67ea9c3182bca6d3f0498cdc1f25a64df57b90"
|
||||
},
|
||||
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
|
||||
"bytes": 13349,
|
||||
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
|
||||
},
|
||||
"geometry/diamond-after.png": {
|
||||
"bytes": 12556,
|
||||
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
|
||||
},
|
||||
"geometry/diamond-before.png": {
|
||||
"bytes": 13228,
|
||||
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
|
||||
},
|
||||
"geometry/diamond-experimental_candidate-metrics.png": {
|
||||
"bytes": 13555,
|
||||
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
|
||||
},
|
||||
"geometry/diamond-reset_only_control-metrics.png": {
|
||||
"bytes": 12982,
|
||||
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
|
||||
},
|
||||
"geometry/fixed_ports-after.png": {
|
||||
"bytes": 11889,
|
||||
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
|
||||
},
|
||||
"geometry/fixed_ports-before.png": {
|
||||
"bytes": 12013,
|
||||
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
|
||||
},
|
||||
"geometry/fixed_ports-experimental_candidate-metrics.png": {
|
||||
"bytes": 12394,
|
||||
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
|
||||
},
|
||||
"geometry/fixed_ports-reset_only_control-metrics.png": {
|
||||
"bytes": 12231,
|
||||
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
|
||||
},
|
||||
"geometry/flat_chain_4-after.png": {
|
||||
"bytes": 12582,
|
||||
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
|
||||
},
|
||||
"geometry/flat_chain_4-before.png": {
|
||||
"bytes": 12723,
|
||||
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
|
||||
},
|
||||
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
|
||||
"bytes": 13405,
|
||||
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
|
||||
},
|
||||
"geometry/flat_chain_4-reset_only_control-metrics.png": {
|
||||
"bytes": 12918,
|
||||
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
|
||||
},
|
||||
"geometry/long_ordinary_labels-after.png": {
|
||||
"bytes": 12643,
|
||||
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
|
||||
},
|
||||
"geometry/long_ordinary_labels-before.png": {
|
||||
"bytes": 12661,
|
||||
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
|
||||
},
|
||||
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
|
||||
"bytes": 13235,
|
||||
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
|
||||
},
|
||||
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
|
||||
"bytes": 12969,
|
||||
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
|
||||
},
|
||||
"geometry/manifest.json": {
|
||||
"bytes": 8099,
|
||||
"sha256": "0102449f730651a92233c4ae959e95e0a58036fe2b1c309224558c496241c741"
|
||||
},
|
||||
"geometry/nested_cross_boundary-after.png": {
|
||||
"bytes": 13344,
|
||||
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
|
||||
},
|
||||
"geometry/nested_cross_boundary-before.png": {
|
||||
"bytes": 13547,
|
||||
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
|
||||
},
|
||||
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
|
||||
"bytes": 13535,
|
||||
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
|
||||
},
|
||||
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
|
||||
"bytes": 13549,
|
||||
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-after.png": {
|
||||
"bytes": 13955,
|
||||
"sha256": "1722ff21eaadd831e00b2176d61f8fa65b083d2fd5b633a196a3335d48ca125e"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-before.png": {
|
||||
"bytes": 14080,
|
||||
"sha256": "78e765c579dd317e26177d0cd05cccc61519638e9198fdd0d344d9b54a95c1ba"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
|
||||
"bytes": 14500,
|
||||
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
|
||||
"bytes": 14531,
|
||||
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
|
||||
"bytes": 14134,
|
||||
"sha256": "ce6bc93dc38fe5b25552c8ebc5e778da175df53992e6a70ded8377fd99372587"
|
||||
},
|
||||
"support/auto-layout-j-comparison-20260925.json": {
|
||||
"bytes": 76669,
|
||||
"sha256": "3d5435686c2d23e97f08340693015ef66d1127726c9b5b5212678f43b3ad6b76"
|
||||
},
|
||||
"support/auto-layout-contact-audit-result-20260925.json": {
|
||||
"bytes": 104481,
|
||||
"sha256": "ec94203f42782d87c0459c251ab226567818e2715bc46a3e9ee0c25a6c15d620"
|
||||
},
|
||||
"support/auto-layout-contact-audit-20260925.py": {
|
||||
"bytes": 9838,
|
||||
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
|
||||
},
|
||||
"support/auto-layout-format-j-20260925.json": {
|
||||
"bytes": 203,
|
||||
"sha256": "5bd0e4b979aedf21bd38e4c41a1521dafffb78c3cccb61cd12dad56d4f4699e9"
|
||||
},
|
||||
"support/run-auto-layout-check-20260925.py": {
|
||||
"bytes": 2771,
|
||||
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
|
||||
},
|
||||
"support/run.py": {
|
||||
"bytes": 13814,
|
||||
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"name": "terminal-join-08656b18.zip",
|
||||
"bytes": 3178939,
|
||||
"sha256": "bd2146237353af05b8667dc7bd728007143a2f1b24ad9f8728fdbc50ffb3368e"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
|
||||
@@ -0,0 +1,565 @@
|
||||
{
|
||||
"scope": "Finite PL/L experiments; no production/native/performance acceptance",
|
||||
"runs": [
|
||||
{
|
||||
"name": "08-lane-tests",
|
||||
"source_commit": "d0be9ff0674373fcf9623daf62bbf50dad02c4df",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"name": "09-penalty-lanes-probe",
|
||||
"source_commit": "d0be9ff0674373fcf9623daf62bbf50dad02c4df",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"name": "10-lanes-core-tests",
|
||||
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"name": "11-lanes-probe",
|
||||
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"name": "12-lanes-clippy",
|
||||
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
|
||||
"exit_code": 0
|
||||
}
|
||||
],
|
||||
"post_run_l_probe_binary": {
|
||||
"bytes": 24202240,
|
||||
"sha256": "3c6a6fd09bc86e7e6b3ff1ace05540c103393d66bbb02c46bf0ebd6214fbabb1"
|
||||
},
|
||||
"members": {
|
||||
"08-lane-tests/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"08-lane-tests/command/context.json": {
|
||||
"bytes": 3478,
|
||||
"sha256": "7f30e52a87c964d86e86229061be72372a9cfc1a3fad9a37c326370c38aec4ad"
|
||||
},
|
||||
"08-lane-tests/command/inputs-after.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
|
||||
},
|
||||
"08-lane-tests/command/inputs-before.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
|
||||
},
|
||||
"08-lane-tests/command/output.log": {
|
||||
"bytes": 670,
|
||||
"sha256": "1b3cc48bee9bb4d564f0479a692b7b20fa6df5da3b8dccfda5d1487b6b93f53e"
|
||||
},
|
||||
"08-lane-tests/command/result.json": {
|
||||
"bytes": 4121,
|
||||
"sha256": "9a48e66ce638944e885e708b3f361ce2d099352e154536a46fafa6bca49af12f"
|
||||
},
|
||||
"08-lane-tests/command/stderr.log": {
|
||||
"bytes": 304,
|
||||
"sha256": "c534ac6e8df5add7c08f663cd516b9a0da947a93127ebda6c378ede9bd42f575"
|
||||
},
|
||||
"08-lane-tests/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"08-lane-tests/orchestration.log": {
|
||||
"bytes": 170,
|
||||
"sha256": "bf1ebdbbdd1955bd7b874592340e3d79a48a145a9b39faec898aaa807133f81a"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/context.json": {
|
||||
"bytes": 3502,
|
||||
"sha256": "4c95894559f60d51fda0e2af09b2ec66abf9dc687d623c1e67c9e042747d0084"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/inputs-after.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/inputs-before.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/output.log": {
|
||||
"bytes": 371062,
|
||||
"sha256": "04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/result.json": {
|
||||
"bytes": 4166,
|
||||
"sha256": "538aa79bcedd4cf646c63d5309ec738be4676e2045715db1035a4f334a536117"
|
||||
},
|
||||
"09-penalty-lanes-probe/command/stderr.log": {
|
||||
"bytes": 279,
|
||||
"sha256": "126be48ed1535d641835bd72b6fc5aa05a9a2120dd2012daa3e30108eb1703e2"
|
||||
},
|
||||
"09-penalty-lanes-probe/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"09-penalty-lanes-probe/orchestration.log": {
|
||||
"bytes": 179,
|
||||
"sha256": "4e398b4fed1ac76d6bd61cb18fe2c50cae2764f040d878006e464c5728428cd3"
|
||||
},
|
||||
"10-lanes-core-tests/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"10-lanes-core-tests/command/context.json": {
|
||||
"bytes": 3655,
|
||||
"sha256": "2ee756c13c33bccf0cb7c87492bb62be5d5203044a066af0af36389059b2181c"
|
||||
},
|
||||
"10-lanes-core-tests/command/inputs-after.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
|
||||
},
|
||||
"10-lanes-core-tests/command/inputs-before.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
|
||||
},
|
||||
"10-lanes-core-tests/command/output.log": {
|
||||
"bytes": 19032,
|
||||
"sha256": "bde8202db1c2f3f407a7dcbf6a1184830d0914e2bbba0e5f7cbd2c55d72d56b4"
|
||||
},
|
||||
"10-lanes-core-tests/command/result.json": {
|
||||
"bytes": 4312,
|
||||
"sha256": "828871867eb7ff0ccfd5953a694ae594ae145e89bf2eca831368297d1ea9b874"
|
||||
},
|
||||
"10-lanes-core-tests/command/stderr.log": {
|
||||
"bytes": 990,
|
||||
"sha256": "df86da47eb1884669f1d0ce14107713ea9afd9e3cbb68becf451a018a1bf7303"
|
||||
},
|
||||
"10-lanes-core-tests/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"10-lanes-core-tests/orchestration.log": {
|
||||
"bytes": 176,
|
||||
"sha256": "6a2f55638fd26b60333bcd61cc1faaa29baaf9041962cbc1cfacd762bfc933e5"
|
||||
},
|
||||
"11-lanes-probe/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"11-lanes-probe/command/context.json": {
|
||||
"bytes": 3494,
|
||||
"sha256": "d8ec80836b09c1859b7d482dbd2ebb0243495be3e022ce2cb5dcc5c47e9464bf"
|
||||
},
|
||||
"11-lanes-probe/command/inputs-after.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
|
||||
},
|
||||
"11-lanes-probe/command/inputs-before.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
|
||||
},
|
||||
"11-lanes-probe/command/output.log": {
|
||||
"bytes": 371182,
|
||||
"sha256": "64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d"
|
||||
},
|
||||
"11-lanes-probe/command/result.json": {
|
||||
"bytes": 4142,
|
||||
"sha256": "feee84c2fde115c22ea865033ff2d136da2aace1f1c8a7423c8add11358366a8"
|
||||
},
|
||||
"11-lanes-probe/command/stderr.log": {
|
||||
"bytes": 278,
|
||||
"sha256": "2e73f2722528e8f80b9e64f722643769e279d822835e9ea47e96cb07eaf51162"
|
||||
},
|
||||
"11-lanes-probe/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"11-lanes-probe/orchestration.log": {
|
||||
"bytes": 171,
|
||||
"sha256": "93c3867e1dc8b07314a7ac03db0d76b641eda2eaad1ad58a61914f1d6ec64794"
|
||||
},
|
||||
"12-lanes-clippy/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"12-lanes-clippy/command/context.json": {
|
||||
"bytes": 3513,
|
||||
"sha256": "eb644e36413cc55e61b7f6aa6162f7f17f21f67911123f951f1ed96c91b30430"
|
||||
},
|
||||
"12-lanes-clippy/command/inputs-after.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
|
||||
},
|
||||
"12-lanes-clippy/command/inputs-before.json": {
|
||||
"bytes": 1730052,
|
||||
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
|
||||
},
|
||||
"12-lanes-clippy/command/output.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"12-lanes-clippy/command/result.json": {
|
||||
"bytes": 4158,
|
||||
"sha256": "ea20c2e64c26667f575b70b598a790aceb1804070c208e5f8f1dd7839e8b0a8f"
|
||||
},
|
||||
"12-lanes-clippy/command/stderr.log": {
|
||||
"bytes": 177,
|
||||
"sha256": "5e1eff044f676ea902db61f76e53375f034cc2cd33c8671a56d11dd4a2aa2936"
|
||||
},
|
||||
"12-lanes-clippy/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"12-lanes-clippy/orchestration.log": {
|
||||
"bytes": 172,
|
||||
"sha256": "44d905169275ce11c8f66e16ce232d750f6b2701e6fb085880e9ad013219d18b"
|
||||
},
|
||||
"pl-geometry/authored_detour_and_label-after.png": {
|
||||
"bytes": 12492,
|
||||
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
|
||||
},
|
||||
"pl-geometry/authored_detour_and_label-before.png": {
|
||||
"bytes": 12468,
|
||||
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
|
||||
},
|
||||
"pl-geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
|
||||
"bytes": 13162,
|
||||
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
|
||||
},
|
||||
"pl-geometry/authored_detour_and_label-reset_only_control-metrics.png": {
|
||||
"bytes": 12777,
|
||||
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
|
||||
},
|
||||
"pl-geometry/chain_7_row_wrap-after.png": {
|
||||
"bytes": 14271,
|
||||
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
|
||||
},
|
||||
"pl-geometry/chain_7_row_wrap-before.png": {
|
||||
"bytes": 13771,
|
||||
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
|
||||
},
|
||||
"pl-geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
|
||||
"bytes": 14396,
|
||||
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
|
||||
},
|
||||
"pl-geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
|
||||
"bytes": 14549,
|
||||
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
|
||||
},
|
||||
"pl-geometry/crossed_bipartite-after.png": {
|
||||
"bytes": 13163,
|
||||
"sha256": "bb809e93b44e802d05430903cf397618fb901efdb6c5ab272574064e20641af6"
|
||||
},
|
||||
"pl-geometry/crossed_bipartite-before.png": {
|
||||
"bytes": 13399,
|
||||
"sha256": "9b7af6a43ec655cdcb05da49b5fffea661d4f5c9a5ae70a0c74c6e7696b066d3"
|
||||
},
|
||||
"pl-geometry/crossed_bipartite-experimental_candidate-metrics.png": {
|
||||
"bytes": 13856,
|
||||
"sha256": "c386b537f077f014e73e99831fdbb57e64ae9709a30afd2909dd50d7443c1899"
|
||||
},
|
||||
"pl-geometry/crossed_bipartite-reset_only_control-metrics.png": {
|
||||
"bytes": 13368,
|
||||
"sha256": "bdcf079498dc2dce5245e47eac8038d736cea7af6176ada13bf682671c70b4b4"
|
||||
},
|
||||
"pl-geometry/diamond-after.png": {
|
||||
"bytes": 12556,
|
||||
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
|
||||
},
|
||||
"pl-geometry/diamond-before.png": {
|
||||
"bytes": 13228,
|
||||
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
|
||||
},
|
||||
"pl-geometry/diamond-experimental_candidate-metrics.png": {
|
||||
"bytes": 13555,
|
||||
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
|
||||
},
|
||||
"pl-geometry/diamond-reset_only_control-metrics.png": {
|
||||
"bytes": 12982,
|
||||
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
|
||||
},
|
||||
"pl-geometry/fixed_ports-after.png": {
|
||||
"bytes": 11889,
|
||||
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
|
||||
},
|
||||
"pl-geometry/fixed_ports-before.png": {
|
||||
"bytes": 12013,
|
||||
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
|
||||
},
|
||||
"pl-geometry/fixed_ports-experimental_candidate-metrics.png": {
|
||||
"bytes": 12394,
|
||||
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
|
||||
},
|
||||
"pl-geometry/fixed_ports-reset_only_control-metrics.png": {
|
||||
"bytes": 12231,
|
||||
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
|
||||
},
|
||||
"pl-geometry/flat_chain_4-after.png": {
|
||||
"bytes": 12582,
|
||||
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
|
||||
},
|
||||
"pl-geometry/flat_chain_4-before.png": {
|
||||
"bytes": 12723,
|
||||
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
|
||||
},
|
||||
"pl-geometry/flat_chain_4-experimental_candidate-metrics.png": {
|
||||
"bytes": 13405,
|
||||
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
|
||||
},
|
||||
"pl-geometry/flat_chain_4-reset_only_control-metrics.png": {
|
||||
"bytes": 12918,
|
||||
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
|
||||
},
|
||||
"pl-geometry/long_ordinary_labels-after.png": {
|
||||
"bytes": 12643,
|
||||
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
|
||||
},
|
||||
"pl-geometry/long_ordinary_labels-before.png": {
|
||||
"bytes": 12661,
|
||||
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
|
||||
},
|
||||
"pl-geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
|
||||
"bytes": 13235,
|
||||
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
|
||||
},
|
||||
"pl-geometry/long_ordinary_labels-reset_only_control-metrics.png": {
|
||||
"bytes": 12969,
|
||||
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
|
||||
},
|
||||
"pl-geometry/manifest.json": {
|
||||
"bytes": 8099,
|
||||
"sha256": "dc9c09882d841e6ba050caabf411de8dd0e868879fe8f0b7a1b44cece9ffde8b"
|
||||
},
|
||||
"pl-geometry/nested_cross_boundary-after.png": {
|
||||
"bytes": 13344,
|
||||
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
|
||||
},
|
||||
"pl-geometry/nested_cross_boundary-before.png": {
|
||||
"bytes": 13547,
|
||||
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
|
||||
},
|
||||
"pl-geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
|
||||
"bytes": 13535,
|
||||
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
|
||||
},
|
||||
"pl-geometry/nested_cross_boundary-reset_only_control-metrics.png": {
|
||||
"bytes": 13549,
|
||||
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
|
||||
},
|
||||
"pl-geometry/two_containers_reversed_children-after.png": {
|
||||
"bytes": 13957,
|
||||
"sha256": "b0911f8afb39313e6ce43661396d6553276d5db53c659937acf87252ed502c6e"
|
||||
},
|
||||
"pl-geometry/two_containers_reversed_children-before.png": {
|
||||
"bytes": 14083,
|
||||
"sha256": "2d42d34af4674bbf1739e85967d743e6fc78c117ef1e7645724c504b006ee881"
|
||||
},
|
||||
"pl-geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
|
||||
"bytes": 14500,
|
||||
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
|
||||
},
|
||||
"pl-geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
|
||||
"bytes": 14531,
|
||||
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
|
||||
},
|
||||
"pl-geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
|
||||
"bytes": 14136,
|
||||
"sha256": "f690678d5697cbec20e64bf92a128a8fd3a1dffe3948fcbe75ad99a4f33de96d"
|
||||
},
|
||||
"support/auto-layout-pl-comparison-20260925.json": {
|
||||
"bytes": 75815,
|
||||
"sha256": "81f57e651a8840aaaeacc085df2eb90174b2e494182f6cd40ccd6d50e7bb531e"
|
||||
},
|
||||
"support/auto-layout-pl-contact-audit-20260925.json": {
|
||||
"bytes": 103918,
|
||||
"sha256": "60ce7e9735ceef50a92d29a0414aafe3d8fb6174dab99eff6397e2abc88e0afa"
|
||||
},
|
||||
"support/auto-layout-pl-binary-20260925.json": {
|
||||
"bytes": 220,
|
||||
"sha256": "00f0ceb0e92a156de2d870e32b1d57d88465e5acedd9c5f5e733f183a750c46e"
|
||||
},
|
||||
"l-geometry/authored_detour_and_label-after.png": {
|
||||
"bytes": 12492,
|
||||
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
|
||||
},
|
||||
"l-geometry/authored_detour_and_label-before.png": {
|
||||
"bytes": 12468,
|
||||
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
|
||||
},
|
||||
"l-geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
|
||||
"bytes": 13162,
|
||||
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
|
||||
},
|
||||
"l-geometry/authored_detour_and_label-reset_only_control-metrics.png": {
|
||||
"bytes": 12777,
|
||||
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
|
||||
},
|
||||
"l-geometry/chain_7_row_wrap-after.png": {
|
||||
"bytes": 14271,
|
||||
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
|
||||
},
|
||||
"l-geometry/chain_7_row_wrap-before.png": {
|
||||
"bytes": 13771,
|
||||
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
|
||||
},
|
||||
"l-geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
|
||||
"bytes": 14396,
|
||||
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
|
||||
},
|
||||
"l-geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
|
||||
"bytes": 14549,
|
||||
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
|
||||
},
|
||||
"l-geometry/crossed_bipartite-after.png": {
|
||||
"bytes": 13144,
|
||||
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
|
||||
},
|
||||
"l-geometry/crossed_bipartite-before.png": {
|
||||
"bytes": 13399,
|
||||
"sha256": "9b7af6a43ec655cdcb05da49b5fffea661d4f5c9a5ae70a0c74c6e7696b066d3"
|
||||
},
|
||||
"l-geometry/crossed_bipartite-experimental_candidate-metrics.png": {
|
||||
"bytes": 13856,
|
||||
"sha256": "c386b537f077f014e73e99831fdbb57e64ae9709a30afd2909dd50d7443c1899"
|
||||
},
|
||||
"l-geometry/crossed_bipartite-reset_only_control-metrics.png": {
|
||||
"bytes": 13349,
|
||||
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
|
||||
},
|
||||
"l-geometry/diamond-after.png": {
|
||||
"bytes": 12556,
|
||||
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
|
||||
},
|
||||
"l-geometry/diamond-before.png": {
|
||||
"bytes": 13228,
|
||||
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
|
||||
},
|
||||
"l-geometry/diamond-experimental_candidate-metrics.png": {
|
||||
"bytes": 13555,
|
||||
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
|
||||
},
|
||||
"l-geometry/diamond-reset_only_control-metrics.png": {
|
||||
"bytes": 12982,
|
||||
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
|
||||
},
|
||||
"l-geometry/fixed_ports-after.png": {
|
||||
"bytes": 11889,
|
||||
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
|
||||
},
|
||||
"l-geometry/fixed_ports-before.png": {
|
||||
"bytes": 12013,
|
||||
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
|
||||
},
|
||||
"l-geometry/fixed_ports-experimental_candidate-metrics.png": {
|
||||
"bytes": 12394,
|
||||
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
|
||||
},
|
||||
"l-geometry/fixed_ports-reset_only_control-metrics.png": {
|
||||
"bytes": 12231,
|
||||
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
|
||||
},
|
||||
"l-geometry/flat_chain_4-after.png": {
|
||||
"bytes": 12582,
|
||||
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
|
||||
},
|
||||
"l-geometry/flat_chain_4-before.png": {
|
||||
"bytes": 12723,
|
||||
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
|
||||
},
|
||||
"l-geometry/flat_chain_4-experimental_candidate-metrics.png": {
|
||||
"bytes": 13405,
|
||||
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
|
||||
},
|
||||
"l-geometry/flat_chain_4-reset_only_control-metrics.png": {
|
||||
"bytes": 12918,
|
||||
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
|
||||
},
|
||||
"l-geometry/long_ordinary_labels-after.png": {
|
||||
"bytes": 12643,
|
||||
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
|
||||
},
|
||||
"l-geometry/long_ordinary_labels-before.png": {
|
||||
"bytes": 12661,
|
||||
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
|
||||
},
|
||||
"l-geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
|
||||
"bytes": 13235,
|
||||
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
|
||||
},
|
||||
"l-geometry/long_ordinary_labels-reset_only_control-metrics.png": {
|
||||
"bytes": 12969,
|
||||
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
|
||||
},
|
||||
"l-geometry/manifest.json": {
|
||||
"bytes": 8099,
|
||||
"sha256": "897b9d42b494bac1e5263a8bab42756c3038403948e6ac76028d86fd6e56ae20"
|
||||
},
|
||||
"l-geometry/nested_cross_boundary-after.png": {
|
||||
"bytes": 13344,
|
||||
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
|
||||
},
|
||||
"l-geometry/nested_cross_boundary-before.png": {
|
||||
"bytes": 13547,
|
||||
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
|
||||
},
|
||||
"l-geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
|
||||
"bytes": 13535,
|
||||
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
|
||||
},
|
||||
"l-geometry/nested_cross_boundary-reset_only_control-metrics.png": {
|
||||
"bytes": 13549,
|
||||
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
|
||||
},
|
||||
"l-geometry/two_containers_reversed_children-after.png": {
|
||||
"bytes": 13957,
|
||||
"sha256": "b0911f8afb39313e6ce43661396d6553276d5db53c659937acf87252ed502c6e"
|
||||
},
|
||||
"l-geometry/two_containers_reversed_children-before.png": {
|
||||
"bytes": 14083,
|
||||
"sha256": "2d42d34af4674bbf1739e85967d743e6fc78c117ef1e7645724c504b006ee881"
|
||||
},
|
||||
"l-geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
|
||||
"bytes": 14500,
|
||||
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
|
||||
},
|
||||
"l-geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
|
||||
"bytes": 14531,
|
||||
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
|
||||
},
|
||||
"l-geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
|
||||
"bytes": 14136,
|
||||
"sha256": "f690678d5697cbec20e64bf92a128a8fd3a1dffe3948fcbe75ad99a4f33de96d"
|
||||
},
|
||||
"support/auto-layout-l-comparison-20260925.json": {
|
||||
"bytes": 76659,
|
||||
"sha256": "e1e23e6c2a50cd384457bb061d5b70a740f586f42767164fad9703ecbb4096a8"
|
||||
},
|
||||
"support/auto-layout-l-contact-audit-20260925.json": {
|
||||
"bytes": 103893,
|
||||
"sha256": "6f6cc674c27d3f43001fe1751ef3b09332caa9ddca396759f5525f811cbe1aaf"
|
||||
},
|
||||
"support/auto-layout-l-binary-20260925.json": {
|
||||
"bytes": 220,
|
||||
"sha256": "9c6d6e20c86237e5d1b917a981f2a5a8612d1c58b6e0706d4701e6c7cc59e06f"
|
||||
},
|
||||
"support/auto-layout-contact-audit-20260925.py": {
|
||||
"bytes": 9838,
|
||||
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
|
||||
},
|
||||
"support/run-auto-layout-check-20260925.py": {
|
||||
"bytes": 2771,
|
||||
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
|
||||
},
|
||||
"support/auto-layout-format-j-20260925.json": {
|
||||
"bytes": 203,
|
||||
"sha256": "5bd0e4b979aedf21bd38e4c41a1521dafffb78c3cccb61cd12dad56d4f4699e9"
|
||||
},
|
||||
"support/run.py": {
|
||||
"bytes": 13814,
|
||||
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"name": "lanes-e8ec6db.zip",
|
||||
"bytes": 3518507,
|
||||
"sha256": "5512b4cbd99e3bf03eb975e25fb980f7b1a95a5cb19f3687fb3d6d83d1839e8f"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
|
||||
@@ -0,0 +1,223 @@
|
||||
{
|
||||
"source_commit": "3d7adff923dee5bed54dfdccc119dbee0c7c2773",
|
||||
"scope": "Transient P coefficient3.0/cap80 experiment, not production acceptance or claim that J tests pass with P.",
|
||||
"post_run_probe_binary": {
|
||||
"bytes": 24156160,
|
||||
"sha256": "8f3ac5aa1fa01be6a8ab664e8ae269f6527b8ffb7e326c2926c8fae7c3d7e366"
|
||||
},
|
||||
"members": {
|
||||
"run/command/changes.patch": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"run/command/context.json": {
|
||||
"bytes": 3504,
|
||||
"sha256": "6f6019b2be69e12e3270d8570e9e4950c93e42e8b3093a0e0324a30f7e5eb0ff"
|
||||
},
|
||||
"run/command/inputs-after.json": {
|
||||
"bytes": 1727969,
|
||||
"sha256": "607febcd0d74d11deaa07a44b8b9cf6c382fd65d55deadb2d8ac7e889797dcf1"
|
||||
},
|
||||
"run/command/inputs-before.json": {
|
||||
"bytes": 1727969,
|
||||
"sha256": "607febcd0d74d11deaa07a44b8b9cf6c382fd65d55deadb2d8ac7e889797dcf1"
|
||||
},
|
||||
"run/command/output.log": {
|
||||
"bytes": 371606,
|
||||
"sha256": "13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7"
|
||||
},
|
||||
"run/command/result.json": {
|
||||
"bytes": 4172,
|
||||
"sha256": "6149122d05d77e02b463edb3dd359b06786bc4468c27d8cd625cbc1bc80c9894"
|
||||
},
|
||||
"run/command/stderr.log": {
|
||||
"bytes": 279,
|
||||
"sha256": "fe5d8d303700ef5b92bfaa95ac1f99a2214e1fc5f6c5ac8d83f6303aa258965b"
|
||||
},
|
||||
"run/environment.json": {
|
||||
"bytes": 9463,
|
||||
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
|
||||
},
|
||||
"run/orchestration.log": {
|
||||
"bytes": 181,
|
||||
"sha256": "db5af22d893966919b9342fd06b99e7e1c82c5c87593544b7762cc85f9a7e45a"
|
||||
},
|
||||
"geometry/authored_detour_and_label-after.png": {
|
||||
"bytes": 12492,
|
||||
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
|
||||
},
|
||||
"geometry/authored_detour_and_label-before.png": {
|
||||
"bytes": 12468,
|
||||
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
|
||||
},
|
||||
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
|
||||
"bytes": 13162,
|
||||
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
|
||||
},
|
||||
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
|
||||
"bytes": 12777,
|
||||
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-after.png": {
|
||||
"bytes": 14271,
|
||||
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-before.png": {
|
||||
"bytes": 13771,
|
||||
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
|
||||
"bytes": 14396,
|
||||
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
|
||||
},
|
||||
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
|
||||
"bytes": 14549,
|
||||
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
|
||||
},
|
||||
"geometry/crossed_bipartite-after.png": {
|
||||
"bytes": 13144,
|
||||
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
|
||||
},
|
||||
"geometry/crossed_bipartite-before.png": {
|
||||
"bytes": 13413,
|
||||
"sha256": "8622726dfdfc01e93fcd2d9d22c6d082e5a169b9dcd59f788e876954431214fd"
|
||||
},
|
||||
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
|
||||
"bytes": 13855,
|
||||
"sha256": "e3cc0a326a2c8b577e40101c5f67ea9c3182bca6d3f0498cdc1f25a64df57b90"
|
||||
},
|
||||
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
|
||||
"bytes": 13349,
|
||||
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
|
||||
},
|
||||
"geometry/diamond-after.png": {
|
||||
"bytes": 12556,
|
||||
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
|
||||
},
|
||||
"geometry/diamond-before.png": {
|
||||
"bytes": 13228,
|
||||
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
|
||||
},
|
||||
"geometry/diamond-experimental_candidate-metrics.png": {
|
||||
"bytes": 13555,
|
||||
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
|
||||
},
|
||||
"geometry/diamond-reset_only_control-metrics.png": {
|
||||
"bytes": 12982,
|
||||
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
|
||||
},
|
||||
"geometry/fixed_ports-after.png": {
|
||||
"bytes": 11889,
|
||||
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
|
||||
},
|
||||
"geometry/fixed_ports-before.png": {
|
||||
"bytes": 12013,
|
||||
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
|
||||
},
|
||||
"geometry/fixed_ports-experimental_candidate-metrics.png": {
|
||||
"bytes": 12394,
|
||||
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
|
||||
},
|
||||
"geometry/fixed_ports-reset_only_control-metrics.png": {
|
||||
"bytes": 12231,
|
||||
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
|
||||
},
|
||||
"geometry/flat_chain_4-after.png": {
|
||||
"bytes": 12582,
|
||||
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
|
||||
},
|
||||
"geometry/flat_chain_4-before.png": {
|
||||
"bytes": 12723,
|
||||
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
|
||||
},
|
||||
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
|
||||
"bytes": 13405,
|
||||
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
|
||||
},
|
||||
"geometry/flat_chain_4-reset_only_control-metrics.png": {
|
||||
"bytes": 12918,
|
||||
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
|
||||
},
|
||||
"geometry/long_ordinary_labels-after.png": {
|
||||
"bytes": 12643,
|
||||
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
|
||||
},
|
||||
"geometry/long_ordinary_labels-before.png": {
|
||||
"bytes": 12661,
|
||||
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
|
||||
},
|
||||
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
|
||||
"bytes": 13235,
|
||||
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
|
||||
},
|
||||
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
|
||||
"bytes": 12969,
|
||||
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
|
||||
},
|
||||
"geometry/manifest.json": {
|
||||
"bytes": 8099,
|
||||
"sha256": "c1b59384878e519efec99757efee571635f30d814247db2f183eebbf9c467a0f"
|
||||
},
|
||||
"geometry/nested_cross_boundary-after.png": {
|
||||
"bytes": 13344,
|
||||
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
|
||||
},
|
||||
"geometry/nested_cross_boundary-before.png": {
|
||||
"bytes": 13547,
|
||||
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
|
||||
},
|
||||
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
|
||||
"bytes": 13535,
|
||||
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
|
||||
},
|
||||
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
|
||||
"bytes": 13549,
|
||||
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-after.png": {
|
||||
"bytes": 13955,
|
||||
"sha256": "1722ff21eaadd831e00b2176d61f8fa65b083d2fd5b633a196a3335d48ca125e"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-before.png": {
|
||||
"bytes": 14092,
|
||||
"sha256": "dcbc521b8e5efd6a201da8a724ed218a9f1331a8abb2eda299a5807828037cb9"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
|
||||
"bytes": 14500,
|
||||
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
|
||||
"bytes": 14531,
|
||||
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
|
||||
},
|
||||
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
|
||||
"bytes": 14134,
|
||||
"sha256": "ce6bc93dc38fe5b25552c8ebc5e778da175df53992e6a70ded8377fd99372587"
|
||||
},
|
||||
"support/auto-layout-p-comparison-20260925.json": {
|
||||
"bytes": 77494,
|
||||
"sha256": "9f228fbe78e1888c5d93e87dddd8d2effc01bab723929a87423c61e23f5cad66"
|
||||
},
|
||||
"support/auto-layout-p-contact-audit-20260925.json": {
|
||||
"bytes": 104912,
|
||||
"sha256": "6f4add5c81f6d16c45efabbefd9e36c9beb637b6823993f0d51adc3e20485ad9"
|
||||
},
|
||||
"support/auto-layout-contact-audit-20260925.py": {
|
||||
"bytes": 9838,
|
||||
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
|
||||
},
|
||||
"support/run-auto-layout-check-20260925.py": {
|
||||
"bytes": 2771,
|
||||
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
|
||||
},
|
||||
"support/run.py": {
|
||||
"bytes": 13814,
|
||||
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"name": "penalty-3d7adff.zip",
|
||||
"bytes": 916568,
|
||||
"sha256": "6b819b01c8012aa72d423443f4dc04ae261f1ee9dc6907f0063c219ff173ad36"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
# #32 Auto-layout source and evaluator map
|
||||
|
||||
Read-only inspection of `.local/auto-layout-20260925`, base715036e132677dd2bc2fb37ed316d93dc9987aec, on2026-09-25. Issue32 explicitly asks automatic creation/removal of bends, attention to connection intersections and labels. No source changes, compiler, GUI, model helper or Gitea writes were performed. No geometric outcomes below are claimed as measured results.
|
||||
|
||||
## Actual surfaces and shared execution
|
||||
|
||||
- `crates/oa-desktop/src/views.rs:443`: saved Architecture diagram toolbar **Auto-layout** sends `Message::Command(Command::Layout(id))`. `model_menu.rs:417`: background **Arrange elements** sends the same command. The generic chooser excludes Scenario, not State, but normal State navigation routes to its dedicated workspace. `behavior/state_menu.rs` returns early for the dedicated State menu, and `state_view.rs` has no equivalent Auto-layout button. State view creation still calls shared Layout (`behavior/state_edit.rs:361–410`); behavior creation batches Layout too (`behavior/creation.rs:477–504`). Distinguish exposed UI from callable core behavior.
|
||||
- `crates/oa-core/src/model.rs:1431`: saved projection kinds are Overview, Decomposition, Allocation, Traceability, FunctionalDataflow, Capabilities, StateMachine and Scenario. `session.rs:947` accepts the first seven; Scenario explicitly refuses and requires its separate geometry operation. Process topology and Scenario lane/message arrangement are separate behavior canvases, not this generic command.
|
||||
- Allocation **Arrange next drag / Alt+A** is a different manual translation workflow (`allocation_drag/arrange.rs`, `app/allocation_drag.rs`, `diagram/work_drag.rs`). Do not silently turn it into automatic graph layout or change its allocation/group/refusal/Undo contracts merely because its label contains Arrange.
|
||||
- `app.rs:3559` applies pending property edits and remaps a changed diagram identity before executing Layout; preserve that admission/identity behavior (`tests.rs::placement_identity_edit_then_drag_and_diagram_identity_then_arrange`). `document.rs:322` prepares/validates a candidate, updates the source bundle with identity provenance, then commits one model/source history entry. Core Session execute at`session.rs:275` likewise records one changed candidate; Undo/Redo swap exact Projects and no-op candidates create no history.
|
||||
- REST transactions at`crates/oa-server/src/routes.rs:1011–1041` accept serialized Command batches including Layout under expected-revision admission, with dry-run and atomic PreparedProject/store commit. Core behavior therefore cannot rely on desktop-only fonts/state. `docs/v2-interface.md` lists Layout convenience commands. CLI exposes check/lint/stabilize/rename-alias, not a direct layout verb. Text/source may store explicit node/route records; parsing/loading them must not implicitly auto-arrange.
|
||||
|
||||
## Current algorithm and why the issue is real
|
||||
|
||||
`session.rs::layout` measures a projection-parent forest, vertically stacks children below headers, and puts roots into rows of four. Roots use an exchange-aware topological-like ordering with alias/ID tie breaks and deterministic cycle fallback. Child order is placement-ID order. It changes node positions/sizes, computes per-node deltas and calls `projection::translated_routes`; it neither scores routed geometry/labels nor generates or removes stored waypoints.
|
||||
|
||||
`projection.rs:81` supplies actual visual parents: nearest placed semantic ancestor; Allocation derives performer grouping from allocation summaries; Traceability is flat; State filters the machine. Ports have owner placements, not independent node placements (`edge_endpoint_placements`). Measurement reserves minimum sizes, State action/internal rows and port footer (`session.rs:967–1006`). Folded descendants still belong to the authored forest; projected visibility and stored layout are distinct.
|
||||
|
||||
The router is **not unaware of crossings or labels**: `routing.rs:457` routes stable edge IDs with a bounded search and previous-edge costs; `crossing_cost:990` penalizes proper crossings and positive collinear overlap separately. All paths settle before automatic label placement; `label_geometry`/`label_collisions:1370–1552` consider node obstacles, earlier labels and all visible strokes. But routing remains greedy, has finite search budgets, and authored label placement bypasses avoidance. Auto-layout never feeds these costs back into node order/spacing. Existing pins constrain paths even after node arrangement, except folded/promoted routes temporarily suspend their custom geometry. Thus a node-only Layout plus pinned greedy routing cannot promise the joint improvement requested by32.
|
||||
|
||||
Base715 uses scalar-estimated label rectangles. The separate #36 measured State multiline layout is not present in this base; do not assume its geometry or acceptance has already integrated. Ordinary labels, association-end labels/stereotypes and State labels also differ in presentation. Parent should coordinate routing-file overlap with #36 before integration, not silently reimplement its measurement policy.
|
||||
|
||||
## Contracts requiring an intentional change
|
||||
|
||||
1. `harness/release-routing-contract.md:143–146` explicitly says Layout preserves pins, translating only equally moved endpoint owners, with Reset routing separate. `crates/oa-desktop/src/guide.rs:360` repeats **Auto-layout preserves pins**. These are directly incompatible with the user's requested automatic bend removal/generation and must be revised for the explicit whole-view operation, with Undo restoring prior authorship.
|
||||
2. `crates/oa-core/tests/release_routing.rs::layout_preserves_authored_route_count_order_labels_and_undo` fixes route list count/order, two pins on each route and exact labels. Replace only the superseded Layout assertions with the new declared output contract plus stronger geometry checks; retain unrelated-diagram exactness and exact Undo. Do not remove all route-preservation tests.
|
||||
3. `state_diagrams.rs::layout_reserves_internal_rows_and_state_routes_retain_hard_pins` combines two things: the **pre-Layout** router must traverse authored pins without mutation; the post-Layout assertions reserve State rows and source roundtrip. Preserve those valid assertions, and rename/split the test if Layout no longer retains pins. Its current body does not actually assert post-Layout pin preservation.
|
||||
4. Decide explicitly whether generated bends remain derived route corners or become persisted editable waypoints. The user asks visible automatic routing improvement, not necessarily a new semantic field. `routing.rs` documents only authored pins in the model; blindly storing every solver corner would turn generated geometry into hard constraints and can cause second-run drift. Whichever representation is chosen needs first/repeat Arrange and manual-after-Arrange tests.
|
||||
5. Define scope for invisible/suspended routes, authored label offsets and explicit attachments. User32 authorizes changing bends; it does not automatically authorize deleting manual semantic-port metadata, every hidden route, or authored label placement. A narrow baseline is reset/rebuild bends for eligible visible edges while retaining attachments, labels and unrelated/hidden records; measure whether that suffices. If an authored label constraint defeats label clearance, report it or make its intentional reset policy explicit instead of pretending the layout is collision-free.
|
||||
|
||||
## Invariants to retain
|
||||
|
||||
Complete elements/relations/traces/types/names/text/IDs/containment/allocations/occurrences remain exact; only the selected diagram's declared presentation fields may differ. Other diagrams, node identities, collapsed flags, view options, unplaced elements and manual port side/fraction metadata remain exact. Automatic port geometry may change with node geometry, but semantic port identity/contract and explicit anchors do not. Existing tests `port_anchors::separate_views_resize_layout_and_hidden_owners_keep_manual_metadata`, `workflows` nested-parent containment, and desktop port/identity tests are relevant sentinels.
|
||||
|
||||
Keep move-one-end pins-fixed and move-both-owners equal-delta translation in `projection::translated_routes`, normal drag/reflow/group previews, reconnect, folding suspension/resumption, Hide/show and Reset routing unchanged unless separately justified. Keep finite geometry and existing point-count/attachment/fraction validation (`validation.rs:650–720`), deterministic bounded failure/fallback, source/JSON roundtrips, dry-run nonmutation, rejected-operation no-history, and exact one-step Undo/Redo. A Layout improvement must not trigger new allocation/reconnect semantics.
|
||||
|
||||
## Independent fixtures and falsifiers to freeze before candidate comparison
|
||||
|
||||
Use hand-declared topology, IDs and geometry; record the old candidate's metrics once, then compare materially different candidates against the same evaluator. Do not use a candidate's own cost function as the acceptance oracle.
|
||||
|
||||
| Fixture | Independent observable requirement |
|
||||
| --- | --- |
|
||||
| Two connected OA activities / SA functions with redundant dogleg and one blocking third card | Explicit Arrange removes obsolete turns; unobstructed edge straightens, blocked edge gains necessary orthogonal turns; semantic endpoints exact, no nonincident-node penetration. Include authored source/target attachments. |
|
||||
| Two containers, each with two children, reversed child-order connections | A planar hand-constructed witness has zero proper crossings; require zero on this bounded case, child containment and preserved port contract. Detect current ID-ordered child stacking weakness. |
|
||||
| Four-node diamond plus return edge, self-loop, parallel and reverse-direction edges | No false cycle/deadlock; meaningful separation of parallel paths; self-loop remains visible; distinguish shared endpoint fans from mid-path overlap. Test swapped UUIDs and stable semantic aliases. |
|
||||
| Five-plus roots and disconnected component | Exposes current every-four-roots wrap and ordering discontinuity. No overlapping cards, reasonable route/area bounds and deterministic repeated result. |
|
||||
| OA/SA nested Allocation with ports, uniform subtree, folded ancestor and hidden route | Child interiors below reserved headers/footer, anchors on owner boundary, no fabricated ports, no semantic reassignment; hidden-route policy explicit; other view exact. |
|
||||
| Traceability mixed OA/SA with duplicate placement sentinels elsewhere | Flat visual graph stays flat, valid edge identities and other diagram exact. |
|
||||
| State machine with composite State, region, entry/exit boundary, internal/action rows and self-transition | State-specific legal boundary crossings, row reservations and no overwritten semantic state; shared Layout initialization remains valid even without a State Auto-layout button. |
|
||||
| Long ordinary/association labels, adjacent parallel labels, and #36 B/W/U State cases once integrated | Independently measure label/node, label/label and unrelated stroke/label intersections using actual displayed geometry; native ink/readability check separate from advance-box arithmetic. |
|
||||
| Dense/nonplanar or contradictory-anchor stress case | Finite time/work and explicit residual warnings/metrics; no claim all crossings can disappear. Preserve exact Undo and input on refusal. |
|
||||
|
||||
## Metrics and acceptance discipline
|
||||
|
||||
Report a vector, not a single opaque beauty score: (1) hard invalid geometry/illegal obstacle penetration and sibling overlap area; (2) label-node/label-label intersection area and other-edge strokes entering labels; (3) distinct proper edge-pair crossings; (4) positive-length collinear shared segments; (5) bend count after duplicate/collinear simplification, path length/stretch and total view bounds. Define endpoint/ancestor exemptions before running: parent-child containment is intentional, a shared semantic endpoint is not a crossing, owner leads and legal State boundary crossings are not nonincident obstacle violations. Deduplicate segment-pair crossing events at the same physical point; count edge pairs separately. Count near-parallel clearance as a separate readability observation, not zero-width intersection.
|
||||
|
||||
Use independent rectangle/segment math and full projected/routed outputs; export SVG and canvas must agree with those outputs. Include authored and derived labels, including association ends. A zero-crossing result obtained by coincident overlapping paths, gigantic detours, clipping labels or hiding edges fails the other metrics. Set fixture-specific route/area ceilings from a feasible manually declared witness rather than arbitrary post-hoc thresholds. Compare a second Arrange for idempotence, input-order permutation for determinism, pure camera changes for model invariance, then source Save/reopen and exact Undo/Redo.
|
||||
|
||||
Unavoidable cases: nonplanar graphs cannot all be planar with distinct nonoverlapping edges; fixed attachment orders, nested boundaries, coincident semantic endpoints and required self-loops can constrain clearance. Existing authored labels can intentionally occlude nodes. Report constrained residuals honestly and avoid turning ordinary automatic layout into deletion of semantic edges or impossible universal no-crossing guarantees.
|
||||
|
||||
The first useful milestone is a finite fixture/evaluator plus an explicit bend/label/hidden-route policy, then a prototype compared against current Layout. No need to expand into unrelated Process/Scenario geometry or redesign manual Arrange drag for this issue.
|
||||
@@ -0,0 +1,39 @@
|
||||
# J terminal-join actual-results independent audit
|
||||
|
||||
Result: the finite experiment supports the terminal-cost asymmetry diagnosis, with a real ordinary-scene overlap regression retained below. It does not establish universally improved routing, complete readability, or #32 acceptance. Static audit only: no compilation, probe rerun, GUI, source edit or publication by reviewer.
|
||||
|
||||
## Evidence and checks
|
||||
|
||||
Tested pin `497c1ad8b39788148c5f03bc8542d6d8e28dbc01`, compared against first probe `e7deea7039bcf31675cffbb462cfeb19d62a7e20`. Run03 command `cargo run --locked --offline -p oa-core --example auto_layout_probe`, Windows x86_64-pc-windows-gnullvm/dev: receipt exit0, failure null, inputs unchanged. Independently verified receipt log hashes. Test02 at the same pin also exit0/unchanged: six summaries132+7+13+18+2+13 =185 passed, zero failed/ignored.
|
||||
|
||||
Independently parsed both raw JSONL outputs, rather than relying only on comparison-helper booleans: all37 variant Projects, complete projected nodes/ports, and per-edge first/last coordinates match exactly. Thus changed area is routed/label bounds, not changed node placement. Independently recomputed every raw pairwise axis-aligned collinear interval total in both runs (74 variant observations); all agree with emitted totals.
|
||||
|
||||
All nine candidate rows report supported, identical repeated input, idempotence, passes2–10 equal first and previous, exact JSON/canonical-single-source roundtrips, no associated errors. Conservation remains true except the intentional authored-detour route reset (`authored_routes_exact=false`). Exact old/new Projects additionally confirm J changed none of these model records. Existing Command::Layout history/Undo/Redo checks pass in all nine rows; the layered candidate remains a pure Project transformation with no candidate-command history evidence. No native GUI evidence.
|
||||
|
||||
## Complete changed quality-vector rows
|
||||
|
||||
| Fixture / variant | Raw sharing old→J | Nonterminal sharing old→J | Other changed fields |
|
||||
|---|---:|---:|---|
|
||||
| diamond / before |136→36|100→0|none|
|
||||
| diamond / layered candidate |82→36|46→0|none|
|
||||
| crossed_bipartite / before |730→872|658→800|bends5→4; length2076→2064|
|
||||
| crossed_bipartite / layered candidate |344→187|272→115|drawing area165360→175960|
|
||||
| two_containers_reversed_children / before |200→54|200→54|none|
|
||||
| two_containers_reversed_children / baseline |148→18|148→18|none|
|
||||
| two_containers_reversed_children / reset control |148→18|148→18|none|
|
||||
|
||||
These are all changes in the comparison's pre-existing12-field quality vector; the remaining30 rows are unchanged. All baseline/reset rows outside the two-container case are unchanged. Seven of nine layered candidate vectors remain unchanged. Raw strict proper crossings remain zero throughout these comparisons; no demonstrated proper-crossing reduction follows.
|
||||
|
||||
The crossed-bipartite BEFORE regression is substantive, not a metric artifact: independent interval sums confirm142 additional shared units. Fewer bends and12 shorter length do not erase that readability tradeoff. Layered bipartite improves157 shared units but retains115 nonterminal units and grows routed drawing area10600 (~6.41%). Viewed its actual offline PNG: distinct vertical channels remain joined to shared horizontal routes. This is not an unambiguous-trace acceptance result. Diamond's remaining36 units are the separately classified common terminal stubs.
|
||||
|
||||
The new point-contact metric has no v1 field to compare directly: do not interpret its mere introduction as newly created contacts. Current layered diamond records2 contacts and bipartite9; the independent contact worker's retrospective audit is pending at this review. Counts classify contacts and do not alone establish readability. Approximate core label bounds, missing renderer/port-label measurements, finite fixture families, axis-only grid state, sequential edge ordering and no global hard-pin optimization remain limits.
|
||||
|
||||
## Binding and recommendation
|
||||
|
||||
- Old raw output SHA256 `21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`.
|
||||
- J raw output SHA256 `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
|
||||
- Run03 result.json SHA256 `57a1f866b2cb67880decd26becf3ac2e7715e38bbd26d3089c47dd62294afa4f`.
|
||||
- Comparison JSON SHA256 `3d5435686c2d23e97f08340693015ef66d1127726c9b5b5212678f43b3ad6b76`.
|
||||
- Geometry manifest SHA256 `0102449f730651a92233c4ae959e95e0a58036fe2b1c309224558c496241c741`; all37 image byte lengths/SHA256 verified. These are offline geometry schematics, not native captures.
|
||||
|
||||
Recommendation: retain J as a successfully isolated scoring correction candidate, with explicit non-monotonic quality results. Before further penalty tuning, use the independently reconstructed contacts and the crossed-bipartite BEFORE regression as falsifiers for any stronger penalty/lane experiment. Keep exact Projects/nodes/ports/endpoints fixed and retain the entire vector, including labels and area. Do not advance directly to broad production quality acceptance based on the layered diamond improvement.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Terminal-join experiment independent source review
|
||||
|
||||
Read-only review of the local candidate based on e7deea7039bcf31675cffbb462cfeb19d62a7e20; no compiler, probe, GUI or helper executed by reviewer. Reviewed routing.rs SHA256 43c2e983a132fd1c687706f5dc6b27867403aae2aa253cdc25195141d24759a5 and the accompanying v2 probe diff. Parent owns formatting, final source pin and execution receipts.
|
||||
|
||||
Recommendation: proceed with the bounded J experiment. No blocking defect found in the changed scoring or contact observer. This is source review, not test success or production acceptance.
|
||||
|
||||
- route_edge supplies the known target continuation only to the final leg, preserving intermediate hard-pin context. The final whole-path score remains unchanged; local selection does not persist or double-charge its score.
|
||||
- fast_path applies the same incoming/outgoing join to both candidate estimates and actual costs. Its Manhattan + two-turn lower bound remains safe for genuine two-bend alternatives because joins/occupied-segment costs are nonnegative. Compacted zero/one-bend alternatives are already represented by the initial L candidates.
|
||||
- grid_path charges the terminal turn before inserting target states into the queue. Manhattan remains an admissible and consistent lower bound for these nonnegative transition additions. Adding a charge after returning the first target would have been incorrect; this implementation avoids that trap.
|
||||
- Zero-length spans retain the existing result and do not invent an arrival vector. turn_cost explicitly returns zero for a zero-length adjacent leg. Whole-route behavior around repeated pins remains covered by existing integration checks rather than a new optimization claim.
|
||||
- New private tests exercise both fast and grid directly, four reflected/rotated diamond witnesses with independently stated complete cost310, absent outgoing context, straight continuation/reversal and degenerate spans. Full route pins, attachment metadata and preview/settled agreement still depend on the parent-planned existing suites; no passing result is inferred from their presence.
|
||||
|
||||
Important limits: grid states remain two axes, not four signed arrival directions, although turn_cost distinguishes reversals. This pre-existing state abstraction is not proof of globally optimal reversal-aware A*. The patch correctly incorporates target cost before arrival-state merging, but does not fix all possible intermediate state dominance issues. Fast routing is still preferred over grid whenever feasible; authored pins are solved leg by leg without global lookahead. Budget/obstacle fallback behavior is unchanged. These are not blockers to this finite asymmetry experiment, but must remain outside its claimed guarantee.
|
||||
|
||||
The probe contact metric is additive: closed point intersections deduplicate by edge pair and EPS-quantized coordinate, OR proper-crossing witnesses, distinguish endpoint/vertex/interior roles, and classify common terminals by both owner and physical coordinate without subtracting them. Positive collinear intervals remain in the separate shared-length metric; a noncollinear witness at their boundary can still count as a point contact. The analytic witnesses include proper, T, bend, endpoint, collinear-touch and overlap cases. These definitions are suitable for the finite orthogonal fixtures, not an exact general floating-point geometry theorem.
|
||||
|
||||
Execution interpretation: compare projected_nodes, projected_ports and exact emitted endpoints against the frozen first run before calling this a fixed-node experiment. The layered prototype itself reroutes while deriving spacing, so identical fixture input alone does not establish identical output placement. Preserve the full metric vector: replacing coincidence with point contacts/crossings or worsening labels must stay visible. No generic node/label layout or native traceability acceptance follows from this experiment.
|
||||
|
||||
## Formatting recheck and source identities
|
||||
|
||||
Original reviewed routing SHA256: `43c2e983a132fd1c687706f5dc6b27867403aae2aa253cdc25195141d24759a5` (measured by reviewer). Original evaluator SHA256: `b7e10e6d346bac93486b075229d8b5b4b74acba05b4bc5778cc60b89a7a6f4d3` (worker/parent-provided identity; reviewer inspected its actual diff).
|
||||
|
||||
Current formatted routing SHA256: `f482f6ef79ee0ef2c615a0ef7fff0d5ad0c56dd080efa8e374b7c29ab9961507`. Current formatted evaluator SHA256: `2cc8d3cb04f8a48bef02008e7b9a0d78aa254009ee85ef7d546df1d04f97ebca`. Both measured by reviewer. Reread full scoped `git diff --ignore-all-space` after formatting: scoring expressions, conditionals, witness coordinates/assertions and observer definitions agree with the pre-format reviewed output. Observed differences are wrapping/indentation and optional trailing commas in routing tests. There is no retained original-byte snapshot for a mechanical whitespace-only comparison; this is an independent source re-review, not a claimed byte-level proof.
|
||||
|
||||
Exact fixed-geometry comparators: per fixture and variant compare full `projected_nodes`, full `projected_ports`, and per-edge first/last coordinates in `routed_edges` with the frozen prior output. Compare endpoint owners to projected edge definitions, and preserve source/target attachment and semantic port identity/anchor metadata in the full Projects. New `route_endpoints` makes the current identity/coordinate association explicit; derive the prior coordinates from prior `routed_edges`, since v1 did not emit that new field. Inspect route/label changes only after those placement/attachment checks, and retain any mismatches as results rather than silently excluding fixtures.
|
||||
@@ -1,3 +0,0 @@
|
||||
# Preserve checksum-bound fixtures and provenance through Git round trips.
|
||||
*.json -text whitespace=cr-at-eol
|
||||
run-f754/*.log -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
|
||||
@@ -1,115 +0,0 @@
|
||||
# Issue 38 bounded geometry experiment
|
||||
|
||||
Core source baseline `715036e132677dd2bc2fb37ed316d93dc9987aec`. The parent compiled
|
||||
the probe at `2aac3e83532166dc45cd3519cc5d89b3e84d57f3`; its first test run passed
|
||||
one test and failed four at admission because the expected warning baseline was
|
||||
incomplete. The corrected baseline awaits rerun; geometry generation did not run.
|
||||
No GUI selection or feature acceptance is claimed. The parent owns execution and
|
||||
publication. Windows only; Linux/WSL excluded.
|
||||
|
||||
The Rust example uses `persistence::decode`, `validation::validate`,
|
||||
`projection::project_view`, and `routing::route_diagram`. It accepts schema JSON or
|
||||
single-file Arcadia source, not a multi-file source bundle. No production modules
|
||||
are changed. It records the complete admitted Project, all projected nodes/ports/
|
||||
edges, semantic endpoint identities, authored and effective route data, settled
|
||||
geometry, labels, warnings, query occluders, and alternate geometric samples.
|
||||
Its input source is read-only. Generation preserves original input bytes alongside
|
||||
normalized complete projects. Individual probe output includes the exact UTF-8
|
||||
input. Output files use create-new, and generation refuses an existing directory.
|
||||
|
||||
## Inputs and independent answer keys
|
||||
|
||||
`mixed-dispatch-original.json` is the exact 32,787-byte archived corpus member
|
||||
`inputs/corpus/mixed_dispatch.json` (see provenance hashes). It has ten function
|
||||
cards, fourteen Functional Exchanges, two saved views, and authored feedback route
|
||||
`...01adbd` with waypoint `(300,-100)`, label fraction `.4`, offset `(-30,-70)`.
|
||||
The secondary view is a conservation sentinel. The original full archive is
|
||||
linked/hashes recorded in `provenance.json`; it is not duplicated here. Only the
|
||||
historical **before** geometry from producer `3e21c1bc...` informed the declared
|
||||
query. The paused boundary-order planner is neither imported nor executed.
|
||||
|
||||
`eight-card-view.json` adds one view to the complete, unchanged
|
||||
`examples/release1/model.json`. Its positions approximate the user's screenshot;
|
||||
the exact saved user view/camera/pins have not been recovered. The mixed OA Process
|
||||
and SA cards use an inferred SA/Traceability view, not SA/Overview. This is a
|
||||
representative reconstruction, not proof of the original projection or identities.
|
||||
No authored routes are invented. All five original views remain unchanged.
|
||||
|
||||
The fixed answer keys were derived from input semantic records and endpoint-owner
|
||||
placements, independently of the router. `eight-answer-key.json` has **12** edges:
|
||||
four Allocation, four PortAllocation, two FunctionalExchange, one BoundaryExchange,
|
||||
and one OA ChainInvolvement. No traces have both endpoints shown. PortAllocation
|
||||
and BoundaryExchange semantic endpoints are ports; projected endpoints are their
|
||||
owner placements. `mixed-answer-key.json` has fourteen FunctionalExchanges.
|
||||
The probe fails if a recognized fixture view's full projected inventory differs,
|
||||
including kind, semantic endpoints, ports, projected endpoints, and trace flag.
|
||||
Do not treat the eight-card count alone as a semantic acceptance check.
|
||||
|
||||
The explicit archived warning baseline is **60**: ten `work_without_behavior_context`,
|
||||
fourteen `exchange_without_behavior_context`, one `missing_system`, and ten
|
||||
`unallocated_leaf`, and 25 `empty_port_contract` diagnostics. The first 24-warning
|
||||
baseline omitted the last three families. [The correction review](warning-baseline-review.md) derives their
|
||||
identities, fields, and messages independently from input records and validation
|
||||
rules; it does not regenerate expectations from observed diagnostics. The release1 baseline is its
|
||||
existing one-warning `expected-diagnostics.json`. Every error, missing warning,
|
||||
extra warning, or changed warning field/message fails admission. No automatic
|
||||
warning acceptance or migration-based fixture replacement is performed.
|
||||
|
||||
## Query policy and limits
|
||||
|
||||
The declared historical query is world `(1982,375)`, zoom `1`. Reproduction requires
|
||||
exactly the two genuine edges `...01adb8` (Actuator dispatch) and `...01adb9`
|
||||
(Operator dispatch copy), zero segment distance, no node/port/label occluder,
|
||||
and common vertical x1982 span y336..414 beyond the common port lead. The flag is
|
||||
false when current routing no longer reproduces this geometry; that is a valid
|
||||
experiment result, not an implementation failure. The eight-card default query
|
||||
`(600,450)` is merely a declared inspection point, not an asserted overlap witness.
|
||||
|
||||
Line candidates use seven screen pixels converted to world units. Port occlusion
|
||||
uses the desktop's **axis-aligned square** half-width `max(10/zoom,10)` world units.
|
||||
It is not a radius-eight circle: `(9,9)` relative to a port center is inside the
|
||||
square at zoom1 and zoom2 although its Euclidean distance exceeds10. The earlier
|
||||
local historical audit's radius-eight assumption is superseded; its original
|
||||
record remains historical and must not be cited as the current port-policy proof.
|
||||
Node rectangles, nonempty ordinary label rectangles, and association-end label
|
||||
rectangles are reported independently. Candidates are distinct edge identities,
|
||||
with every matching segment recorded; a bend does not count as two edges.
|
||||
|
||||
Alternate access is a conservative sample at each segment's quarter/middle/three-
|
||||
quarter points and each label center across the complete scene. A positive result
|
||||
identifies geometric access under this query policy; a negative result proves
|
||||
nothing about global accessibility. Native selected handles, gesture state,
|
||||
viewport clipping, Inspector selection, keyboard behavior, pan/redraw, and actual
|
||||
input dispatch are excluded. Ordinary labels precede association labels in desktop
|
||||
dispatch; this probe conservatively rejects either overlap for an unoccluded sample.
|
||||
It never claims native selection or global inaccessibility.
|
||||
|
||||
Read-only Project equality is a capture/conservation control, not an edit/undo test.
|
||||
Neither automatic route stability after edits nor preview/committed settlement
|
||||
identity is promised. Native evaluation must separately cover unaided tracing,
|
||||
assisted selection, creating an intended relation in the populated scene, moving
|
||||
labels/connections, undo/redo, save/reload, and preservation of authored metadata.
|
||||
Inherited navigation defects (#43) must be recorded separately from routing (#38).
|
||||
|
||||
## Run and review
|
||||
|
||||
The first completed current-router run at `f754ad85` passes all five tests and
|
||||
both generation/query commands. [Results and independent interpretation](run-results.md)
|
||||
link exact artifacts and retained warning-baseline failures. Native workflows
|
||||
and any production improvement remain unverified.
|
||||
|
||||
From the pinned worktree, with a fresh output path:
|
||||
|
||||
```powershell
|
||||
cargo test --locked -p oa-core --example diagram_readability_probe
|
||||
cargo run --locked -p oa-core --example diagram_readability_probe -- generate .local/issue38-probe-run01
|
||||
cargo run --locked -p oa-core --example diagram_readability_probe -- probe harness/experiments/diagram-readability-20260929/mixed-dispatch-original.json harness/experiments/diagram-readability-20260929/mixed-dispatch-expected-diagnostics.json 00000000-0000-0000-0000-0000000186a1 1982 375 1 .local/issue38-probe-query01.json
|
||||
```
|
||||
|
||||
Record `git rev-parse HEAD`, local diff, executable hash, Rust version, commands,
|
||||
stdout/stderr, and output hashes. Verify `provenance.json` source/input SHA256s before
|
||||
making a pinned-router claim. The output's declared base is not executable identity.
|
||||
Tests check original-project conservation, full semantic inventories, sentinel and
|
||||
authored route preservation, deterministic snapshots, failed admission, the port
|
||||
corner, and analytical distinct-edge/label controls. Reuse current generated
|
||||
geometry for subsequent native work; do not relabel historical geometry as a new run.
|
||||
@@ -1,134 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "09eaa992-4cdf-5ea3-b748-f10fd74b8cba",
|
||||
"kind": "PortAllocation",
|
||||
"source": "e6d69cbd-99d7-596b-bbe3-dada6118a600",
|
||||
"target": "d2113fb0-a531-54ef-9484-13951b00ab8f",
|
||||
"source_port": "e6d69cbd-99d7-596b-bbe3-dada6118a600",
|
||||
"target_port": "d2113fb0-a531-54ef-9484-13951b00ab8f",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000102",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000105",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "3cc9ab52-2b00-57fd-8709-aabc75e5d3e3",
|
||||
"kind": "Allocation",
|
||||
"source": "435bf87c-73fd-5e4d-978a-4c471bc9eaf0",
|
||||
"target": "09342ccb-044b-5483-ac58-87dc3cf7831c",
|
||||
"source_port": null,
|
||||
"target_port": null,
|
||||
"projected_source": "00000000-0038-4000-8000-000000000104",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000106",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "55ec4dbf-bd17-5b0c-b3a3-95b2194aa8b9",
|
||||
"kind": "PortAllocation",
|
||||
"source": "98d411e7-7c65-5c3f-b543-8bf0f2522ea2",
|
||||
"target": "24a6850e-b819-57e0-af88-ca4ab76581b7",
|
||||
"source_port": "98d411e7-7c65-5c3f-b543-8bf0f2522ea2",
|
||||
"target_port": "24a6850e-b819-57e0-af88-ca4ab76581b7",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000104",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000103",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "568c5c01-de21-52a2-83bd-afdddc158085",
|
||||
"kind": "PortAllocation",
|
||||
"source": "98d411e7-7c65-5c3f-b543-8bf0f2522ea2",
|
||||
"target": "391af7c4-b07d-53a7-8ddd-5c81461fc4f8",
|
||||
"source_port": "98d411e7-7c65-5c3f-b543-8bf0f2522ea2",
|
||||
"target_port": "391af7c4-b07d-53a7-8ddd-5c81461fc4f8",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000104",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000108",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "628cb4fc-fe63-5f6b-b364-6268f26b5740",
|
||||
"kind": "ChainInvolvement",
|
||||
"source": "022d3cfa-bbaf-5e13-924a-8e55099b8745",
|
||||
"target": "6a30b763-cc51-546d-907f-5c63657cfd03",
|
||||
"source_port": null,
|
||||
"target_port": null,
|
||||
"projected_source": "00000000-0038-4000-8000-000000000101",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000107",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "63009b5f-539e-5914-b630-ec6b7fefb4d5",
|
||||
"kind": "BoundaryExchange",
|
||||
"source": "98d411e7-7c65-5c3f-b543-8bf0f2522ea2",
|
||||
"target": "e6d69cbd-99d7-596b-bbe3-dada6118a600",
|
||||
"source_port": "98d411e7-7c65-5c3f-b543-8bf0f2522ea2",
|
||||
"target_port": "e6d69cbd-99d7-596b-bbe3-dada6118a600",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000104",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000102",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "684eadc3-e670-5779-a60f-bbc9a5bfb062",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "9497e10f-04c4-5586-8738-2464a6f00bd4",
|
||||
"target": "d75eb3fa-a27d-52d5-8782-8b342b3865f6",
|
||||
"source_port": "994faed7-dbc8-5b96-9d62-7604ac0fbc3a",
|
||||
"target_port": "391af7c4-b07d-53a7-8ddd-5c81461fc4f8",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000105",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000108",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"kind": "Allocation",
|
||||
"source": "c05b9422-b9da-5de5-b21d-07ad23bd2b8a",
|
||||
"target": "9497e10f-04c4-5586-8738-2464a6f00bd4",
|
||||
"source_port": null,
|
||||
"target_port": null,
|
||||
"projected_source": "00000000-0038-4000-8000-000000000102",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000105",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "93474111-f23e-56c1-b61b-b7c2396b91bd",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "dddae020-a444-5d48-acc8-139d2696a672",
|
||||
"target": "9497e10f-04c4-5586-8738-2464a6f00bd4",
|
||||
"source_port": "24a6850e-b819-57e0-af88-ca4ab76581b7",
|
||||
"target_port": "d2113fb0-a531-54ef-9484-13951b00ab8f",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000103",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000105",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "9b9356d7-2db2-5a94-a47e-ea892cf02afe",
|
||||
"kind": "Allocation",
|
||||
"source": "435bf87c-73fd-5e4d-978a-4c471bc9eaf0",
|
||||
"target": "dddae020-a444-5d48-acc8-139d2696a672",
|
||||
"source_port": null,
|
||||
"target_port": null,
|
||||
"projected_source": "00000000-0038-4000-8000-000000000104",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000103",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "b76bf8de-2fa4-563f-a540-dd30f30e6c49",
|
||||
"kind": "Allocation",
|
||||
"source": "435bf87c-73fd-5e4d-978a-4c471bc9eaf0",
|
||||
"target": "d75eb3fa-a27d-52d5-8782-8b342b3865f6",
|
||||
"source_port": null,
|
||||
"target_port": null,
|
||||
"projected_source": "00000000-0038-4000-8000-000000000104",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000108",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "e53b7a40-e8a3-5b3f-826d-c2b5c164a84a",
|
||||
"kind": "PortAllocation",
|
||||
"source": "e6d69cbd-99d7-596b-bbe3-dada6118a600",
|
||||
"target": "994faed7-dbc8-5b96-9d62-7604ac0fbc3a",
|
||||
"source_port": "e6d69cbd-99d7-596b-bbe3-dada6118a600",
|
||||
"target_port": "994faed7-dbc8-5b96-9d62-7604ac0fbc3a",
|
||||
"projected_source": "00000000-0038-4000-8000-000000000102",
|
||||
"projected_target": "00000000-0038-4000-8000-000000000105",
|
||||
"trace": false
|
||||
}
|
||||
]
|
||||
@@ -1,132 +0,0 @@
|
||||
{
|
||||
"id": "00000000-0038-4000-8000-000000000001",
|
||||
"alias": "issue38_representative_mixed",
|
||||
"name": "Issue 38 representative eight-card mixed view",
|
||||
"description": "Research approximation of screenshot positions; not recovered user source. Traceability inferred from OA Process with SA Functions. No authored routes inferred.",
|
||||
"layer": "Sa",
|
||||
"projection": "Traceability",
|
||||
"nodes": {
|
||||
"00000000-0038-4000-8000-000000000101": {
|
||||
"id": "00000000-0038-4000-8000-000000000101",
|
||||
"alias": "issue38_oa_assessment_procedure",
|
||||
"element": "022d3cfa-bbaf-5e13-924a-8e55099b8745",
|
||||
"position": {
|
||||
"x": 314,
|
||||
"y": 40
|
||||
},
|
||||
"size": {
|
||||
"width": 243,
|
||||
"height": 101
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000102": {
|
||||
"id": "00000000-0038-4000-8000-000000000102",
|
||||
"alias": "issue38_sa_technician",
|
||||
"element": "c05b9422-b9da-5de5-b21d-07ad23bd2b8a",
|
||||
"position": {
|
||||
"x": 1180,
|
||||
"y": 18
|
||||
},
|
||||
"size": {
|
||||
"width": 265,
|
||||
"height": 143
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000103": {
|
||||
"id": "00000000-0038-4000-8000-000000000103",
|
||||
"alias": "issue38_sa_assess",
|
||||
"element": "dddae020-a444-5d48-acc8-139d2696a672",
|
||||
"position": {
|
||||
"x": 54,
|
||||
"y": 245
|
||||
},
|
||||
"size": {
|
||||
"width": 265,
|
||||
"height": 143
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000104": {
|
||||
"id": "00000000-0038-4000-8000-000000000104",
|
||||
"alias": "issue38_sa_control",
|
||||
"element": "435bf87c-73fd-5e4d-978a-4c471bc9eaf0",
|
||||
"position": {
|
||||
"x": 736,
|
||||
"y": 245
|
||||
},
|
||||
"size": {
|
||||
"width": 265,
|
||||
"height": 143
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000105": {
|
||||
"id": "00000000-0038-4000-8000-000000000105",
|
||||
"alias": "issue38_sa_repair",
|
||||
"element": "9497e10f-04c4-5586-8738-2464a6f00bd4",
|
||||
"position": {
|
||||
"x": 1083,
|
||||
"y": 343
|
||||
},
|
||||
"size": {
|
||||
"width": 266,
|
||||
"height": 143
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000106": {
|
||||
"id": "00000000-0038-4000-8000-000000000106",
|
||||
"alias": "issue38_sa_reset",
|
||||
"element": "09342ccb-044b-5483-ac58-87dc3cf7831c",
|
||||
"position": {
|
||||
"x": 227,
|
||||
"y": 516
|
||||
},
|
||||
"size": {
|
||||
"width": 266,
|
||||
"height": 119
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000107": {
|
||||
"id": "00000000-0038-4000-8000-000000000107",
|
||||
"alias": "issue38_oa_triage",
|
||||
"element": "6a30b763-cc51-546d-907f-5c63657cfd03",
|
||||
"position": {
|
||||
"x": 1317,
|
||||
"y": 581
|
||||
},
|
||||
"size": {
|
||||
"width": 243,
|
||||
"height": 103
|
||||
},
|
||||
"collapsed": false
|
||||
},
|
||||
"00000000-0038-4000-8000-000000000108": {
|
||||
"id": "00000000-0038-4000-8000-000000000108",
|
||||
"alias": "issue38_sa_confirm",
|
||||
"element": "d75eb3fa-a27d-52d5-8782-8b342b3865f6",
|
||||
"position": {
|
||||
"x": 227,
|
||||
"y": 689
|
||||
},
|
||||
"size": {
|
||||
"width": 266,
|
||||
"height": 143
|
||||
},
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
"routes": [],
|
||||
"view_options": {
|
||||
"work_contexts": "All",
|
||||
"participant_categories": "All",
|
||||
"coverage": "All",
|
||||
"hidden_edges": [],
|
||||
"exchange_labels": "Name",
|
||||
"work_categories": "All",
|
||||
"relation_kinds": "All"
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb0",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018704",
|
||||
"target": "00000000-0000-0000-0000-000000018708",
|
||||
"source_port": "edb626b5-7d99-5015-9faf-71a06232d86e",
|
||||
"target_port": "ebfcf690-4ac5-5976-864c-337d844b6cd6",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018705",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018709",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb1",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018706",
|
||||
"target": "00000000-0000-0000-0000-000000018708",
|
||||
"source_port": "d9647cdb-2fcd-5b3f-94b4-ed2a3b8ebf66",
|
||||
"target_port": "ebfcf690-4ac5-5976-864c-337d844b6cd6",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018707",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018709",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb2",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018708",
|
||||
"target": "00000000-0000-0000-0000-00000001870a",
|
||||
"source_port": "9244d718-d53a-54cb-a920-5b5312576da6",
|
||||
"target_port": "14c74a31-2041-59ac-877a-bc8aa0548896",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018709",
|
||||
"projected_target": "00000000-0000-0000-0000-00000001870b",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb3",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018708",
|
||||
"target": "00000000-0000-0000-0000-00000001870c",
|
||||
"source_port": "9244d718-d53a-54cb-a920-5b5312576da6",
|
||||
"target_port": "fe1b5efc-983a-593c-a02f-affd40ff5a2f",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018709",
|
||||
"projected_target": "00000000-0000-0000-0000-00000001870d",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb4",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-00000001870a",
|
||||
"target": "00000000-0000-0000-0000-00000001870e",
|
||||
"source_port": "b4b5d6dc-a2b2-59b0-8898-32dc2e7aa906",
|
||||
"target_port": "d865e245-0fe6-5c21-a872-d57863a1f857",
|
||||
"projected_source": "00000000-0000-0000-0000-00000001870b",
|
||||
"projected_target": "00000000-0000-0000-0000-00000001870f",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb5",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-00000001870c",
|
||||
"target": "00000000-0000-0000-0000-00000001870e",
|
||||
"source_port": "f9d7dbf7-a221-5e51-a58f-530d4ca176e7",
|
||||
"target_port": "51641731-5387-5d58-9bcb-2074acdbe23d",
|
||||
"projected_source": "00000000-0000-0000-0000-00000001870d",
|
||||
"projected_target": "00000000-0000-0000-0000-00000001870f",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb6",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-00000001870e",
|
||||
"target": "00000000-0000-0000-0000-000000018710",
|
||||
"source_port": "224d8f5f-2a81-5315-b7b6-24fe0cd9e95d",
|
||||
"target_port": "406e76e5-affd-59a2-bf1b-c3b3b22d3dd2",
|
||||
"projected_source": "00000000-0000-0000-0000-00000001870f",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018711",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb7",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018710",
|
||||
"target": "00000000-0000-0000-0000-000000018712",
|
||||
"source_port": "8661fe68-51aa-5c8c-827f-e7abea0f6b66",
|
||||
"target_port": "1c6a0a70-81b3-5c39-a2fd-c3d5b9a112c0",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018711",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018713",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb8",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018712",
|
||||
"target": "00000000-0000-0000-0000-000000018714",
|
||||
"source_port": "169224b3-b692-540d-ac73-1435e2a87b04",
|
||||
"target_port": "b1949371-949b-5cb5-acab-485dc4de2e80",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018713",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018715",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adb9",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018712",
|
||||
"target": "00000000-0000-0000-0000-000000018716",
|
||||
"source_port": "169224b3-b692-540d-ac73-1435e2a87b04",
|
||||
"target_port": "01abf25b-82c2-51bc-adbc-73cf6f411b2d",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018713",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018717",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adba",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018716",
|
||||
"target": "00000000-0000-0000-0000-000000018714",
|
||||
"source_port": "bbee14f0-a8d5-5a0d-90e3-01f2d4c5e088",
|
||||
"target_port": "e9dc0338-4237-5cc0-9e7f-7031b51c4772",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018717",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018715",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adbb",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-00000001870c",
|
||||
"target": "00000000-0000-0000-0000-000000018714",
|
||||
"source_port": "7d27cb1e-8dc7-5ebe-9407-a1d05e547562",
|
||||
"target_port": "193bd9b2-e1dd-5764-8f41-777884d3a5ea",
|
||||
"projected_source": "00000000-0000-0000-0000-00000001870d",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018715",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adbc",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018706",
|
||||
"target": "00000000-0000-0000-0000-00000001870c",
|
||||
"source_port": "2fcb392a-80e8-5be4-990c-79de2be0a19b",
|
||||
"target_port": "fdf21c35-cd98-5e9a-9a35-faa453f137ca",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018707",
|
||||
"projected_target": "00000000-0000-0000-0000-00000001870d",
|
||||
"trace": false
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000001adbd",
|
||||
"kind": "FunctionalExchange",
|
||||
"source": "00000000-0000-0000-0000-000000018710",
|
||||
"target": "00000000-0000-0000-0000-000000018704",
|
||||
"source_port": "6f72f5b2-e6c2-5700-a7d5-f945d076fcb8",
|
||||
"target_port": "e3f59e03-53c7-5d99-97f0-f52542e939c7",
|
||||
"projected_source": "00000000-0000-0000-0000-000000018711",
|
||||
"projected_target": "00000000-0000-0000-0000-000000018705",
|
||||
"trace": false
|
||||
}
|
||||
]
|
||||
@@ -1,422 +0,0 @@
|
||||
[
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018704",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018706",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018708",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001870a",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001870c",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001870e",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018710",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018712",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018714",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Include this leaf activity/function in a process/chain or scenario through a work action or exchange occurrence.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018716",
|
||||
"code": "work_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb0",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb1",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb2",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb3",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb4",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb5",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb6",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb7",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb8",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adb9",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adba",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adbb",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adbc",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"message": "Use this exchange in a process/chain or scenario.",
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001adbd",
|
||||
"code": "exchange_without_behavior_context",
|
||||
"field": null
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-0000000186a0",
|
||||
"code": "missing_system",
|
||||
"field": "elements",
|
||||
"message": "Identify the SA system of interest."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018704",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Sensor A' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018706",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Sensor B' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018708",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Ingest' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001870a",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Validate' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001870c",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Archive' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-00000001870e",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Correlate' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018710",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Plan' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018712",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Dispatch' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018714",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Actuator' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "00000000-0000-0000-0000-000000018716",
|
||||
"code": "unallocated_leaf",
|
||||
"field": "allocation",
|
||||
"message": "Allocate leaf 'Operator' to a performer."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "01abf25b-82c2-51bc-adbc-73cf6f411b2d",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "14c74a31-2041-59ac-877a-bc8aa0548896",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "169224b3-b692-540d-ac73-1435e2a87b04",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "193bd9b2-e1dd-5764-8f41-777884d3a5ea",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "1c6a0a70-81b3-5c39-a2fd-c3d5b9a112c0",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "224d8f5f-2a81-5315-b7b6-24fe0cd9e95d",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "2fcb392a-80e8-5be4-990c-79de2be0a19b",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "406e76e5-affd-59a2-bf1b-c3b3b22d3dd2",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "51641731-5387-5d58-9bcb-2074acdbe23d",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "6f72f5b2-e6c2-5700-a7d5-f945d076fcb8",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "7d27cb1e-8dc7-5ebe-9407-a1d05e547562",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "8661fe68-51aa-5c8c-827f-e7abea0f6b66",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "9244d718-d53a-54cb-a920-5b5312576da6",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "b1949371-949b-5cb5-acab-485dc4de2e80",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "b4b5d6dc-a2b2-59b0-8898-32dc2e7aa906",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "bbee14f0-a8d5-5a0d-90e3-01f2d4c5e088",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "d865e245-0fe6-5c21-a872-d57863a1f857",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "d9647cdb-2fcd-5b3f-94b4-ed2a3b8ebf66",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "e3f59e03-53c7-5d99-97f0-f52542e939c7",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "e9dc0338-4237-5cc0-9e7f-7031b51c4772",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "ebfcf690-4ac5-5976-864c-337d844b6cd6",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "edb626b5-7d99-5015-9faf-71a06232d86e",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "f9d7dbf7-a221-5e51-a58f-530d4ca176e7",
|
||||
"code": "empty_port_contract",
|
||||
"field": "outgoing_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "fdf21c35-cd98-5e9a-9a35-faa453f137ca",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
},
|
||||
{
|
||||
"severity": "Warning",
|
||||
"element": "fe1b5efc-983a-593c-a02f-affd40ff5a2f",
|
||||
"code": "empty_port_contract",
|
||||
"field": "incoming_items",
|
||||
"message": "This function port has no declared exchange items."
|
||||
}
|
||||
]
|
||||
@@ -1,103 +0,0 @@
|
||||
{
|
||||
"declared_base": "715036e132677dd2bc2fb37ed316d93dc9987aec",
|
||||
"status": "Completed Windows current-router run at f754ad85d3674a709d10054e6fe23079f977c547: formatting, five tests, generation and separate query pass. Initial failed24 run preserved; native workflows remain unverified. See run-results.md and run-f754/receipt.json.",
|
||||
"files": [
|
||||
{
|
||||
"path": "crates/oa-core/src/model.rs",
|
||||
"bytes": 68387,
|
||||
"sha256": "05a6bd5eef14c77e7cafd2bc72eb3bb6b19f33c6d06184b4e7d21173a2684078"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/persistence.rs",
|
||||
"bytes": 31774,
|
||||
"sha256": "1c01474f906a63e552c0d590b272c95821c00a100b3e79e58e67dbbeac341a14"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/projection.rs",
|
||||
"bytes": 21687,
|
||||
"sha256": "3521bf3041502f3a3a970d7799894a5ae16c1e8da754deeea5290ac1f8ba11e8"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/routing.rs",
|
||||
"bytes": 53958,
|
||||
"sha256": "b377fe80cece3892d64f62ba5e1578d8974eeefc2a317620f343a86f2f257fbd"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/routing/attachments.rs",
|
||||
"bytes": 5918,
|
||||
"sha256": "cfb4200cdb99e4d86eb6e5ac1b123e4075fb7d4c788860d154365ad8ece139d7"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/projection/port_layout.rs",
|
||||
"bytes": 13474,
|
||||
"sha256": "a08d17d10a58bb8b206dd001b19b91d5aa3a9f743b298a4da57d503223c20079"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/validation.rs",
|
||||
"bytes": 113436,
|
||||
"sha256": "f440bfe0f6493e5155eb377eaa766f903abea6006c02325a4b1f09a0b349b8f8"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/validation/coverage.rs",
|
||||
"bytes": 6478,
|
||||
"sha256": "b08e4b344ecad055714168c83beff7fe29ba4edc53edbffa2eae04e5580a4d5f"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-desktop/src/diagram.rs",
|
||||
"bytes": 124738,
|
||||
"sha256": "3170397b82236d6db2a57a1bb860c3c44fd8ec16172701e6784d4bf1314d140f"
|
||||
},
|
||||
{
|
||||
"path": "examples/release1/model.json",
|
||||
"bytes": 134520,
|
||||
"sha256": "ef0ef4006c3e09d5db6e1b621256b3f7d6642f3a7b09cc34607cfbcca830c727"
|
||||
},
|
||||
{
|
||||
"path": "harness/experiments/diagram-readability-20260929/mixed-dispatch-original.json",
|
||||
"bytes": 32787,
|
||||
"sha256": "81d25af021cbad18af4262a220ba60372e51ca19083b7e80f2b19196baf05990"
|
||||
},
|
||||
{
|
||||
"path": "harness/experiments/diagram-readability-20260929/eight-card-view.json",
|
||||
"bytes": 3641,
|
||||
"sha256": "f851e7e96fc6f5b1edb328b94eb991aa8e94b14cc1bcd07b2c42d32310c4527b"
|
||||
},
|
||||
{
|
||||
"path": "harness/experiments/diagram-readability-20260929/mixed-dispatch-expected-diagnostics.json",
|
||||
"bytes": 14337,
|
||||
"sha256": "be6747f4bec4f285b411dfbc934ab63ee46e64403354652d73ec7a801d1c0b2d"
|
||||
},
|
||||
{
|
||||
"path": "harness/experiments/diagram-readability-20260929/mixed-answer-key.json",
|
||||
"bytes": 6683,
|
||||
"sha256": "1696f06e8a4099c2863ad6a5c444ca41ade0848a183b7cd8311400553a0c3d5f"
|
||||
},
|
||||
{
|
||||
"path": "harness/experiments/diagram-readability-20260929/eight-answer-key.json",
|
||||
"bytes": 5337,
|
||||
"sha256": "8968fcc625e8584168ebb6b82f622307bdeb3db4c9c4fdbbc9fbdde3683a6efb"
|
||||
},
|
||||
{
|
||||
"path": "crates/oa-core/src/ports.rs",
|
||||
"bytes": 45413,
|
||||
"sha256": "5cac12eea70a54ebebbd6be77b63ce92e3195325c4bc7d27705c518686cbac80"
|
||||
}
|
||||
],
|
||||
"historical_archive_url": "http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/raw/commit/4fcb65c0d3ec7aabf2315bb3f08b64a7cdd2af99/harness/experiments/boundary-order-20260925/evidence/boundary-order-3e21c1bc.zip",
|
||||
"historical_archive_sha256": "bb6b896ff2401290869a904f7768ebb52b6f0ab36fada06badbe9abb301c37b8",
|
||||
"historical_producer": "3e21c1bca245944ae0ec7bb02aaa920f45f2cc30",
|
||||
"historical_geometry": "before only; candidate planner is paused and not used",
|
||||
"probe_source": {
|
||||
"path": "crates/oa-core/examples/diagram_readability_probe.rs",
|
||||
"sha256": "41e2d5b3f170138b87bf30c9b40971c221a62864558294db2be4e61b7b139989"
|
||||
},
|
||||
"initial_test_failure": {
|
||||
"source_commit": "2aac3e83532166dc45cd3519cc5d89b3e84d57f3",
|
||||
"log": ".local/probe-tests-failed24.log",
|
||||
"log_sha256": "897de362a2d001a83a6880138bc498a28b92602a350ac25405ee38fe81124cc8",
|
||||
"result": "1 passed; 4 failed admission; geometry generation not run",
|
||||
"correction": "Add 1 missing_system, 10 unallocated_leaf, and 25 empty_port_contract warnings from model records and validation/ports rules; no model or probe changes",
|
||||
"rationale": "warning-baseline-review.md"
|
||||
},
|
||||
"baseline_review": "Independent critic verified all 60 exact rows, no duplicates, original 24 rows unchanged, and original input hash preserved. Rerun pending."
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
Compiling oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
|
||||
Finished `dev` profile [unoptimized] target(s) in 1.97s
|
||||
Running `C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\examples\diagram_readability_probe.exe generate .local/issue38-probe-run01`
|
||||
@@ -1,2 +0,0 @@
|
||||
Finished `dev` profile [unoptimized] target(s) in 0.28s
|
||||
Running `C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\examples\diagram_readability_probe.exe probe harness/experiments/diagram-readability-20260929/mixed-dispatch-original.json harness/experiments/diagram-readability-20260929/mixed-dispatch-expected-diagnostics.json 00000000-0000-0000-0000-0000000186a1 1982 375 1 .local/issue38-probe-query01.json`
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"source": "f754ad85d3674a709d10054e6fe23079f977c547",
|
||||
"recorded_utc": "2026-10-02T00:55:33.621109+00:00",
|
||||
"compiler": "rustc 1.98.1 (48a229cea 2026-09-01)",
|
||||
"target": "x86_64-pc-windows-gnullvm",
|
||||
"profile": "dev/unoptimized",
|
||||
"executable": {
|
||||
"bytes": 22633984,
|
||||
"sha256": "d94f86b2f4af594b27960cfa169fd681adb9b3a5eae2928dd72c541bc2db1c57"
|
||||
},
|
||||
"artifacts": {
|
||||
"mixed-dispatch-geometry.json": {
|
||||
"bytes": 122181,
|
||||
"sha256": "651707cba81ae78802cd21bd1aacc9b58a7b9239953f7395cef3b2fb8a5aa5ee"
|
||||
},
|
||||
"eight-card-representative-geometry.json": {
|
||||
"bytes": 206818,
|
||||
"sha256": "2c3e86e58f48272b818e764a339902599b502cb8b718f3ed8de8593651682f2c"
|
||||
},
|
||||
"query-mixed.json": {
|
||||
"bytes": 158526,
|
||||
"sha256": "09cffd48e67f619d5bb9edd8e684d0dba5289b303de4d2cf118b0ec670d8e9b7"
|
||||
},
|
||||
"fmt.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"tests.log": {
|
||||
"bytes": 837,
|
||||
"sha256": "b15549bf4400aa71fe7944bf53772dde1772aae74b89f3bce48f406cdbe0d3b9"
|
||||
},
|
||||
"generate.log": {
|
||||
"bytes": 292,
|
||||
"sha256": "3ca7a0a6b3b4181783bf7e15fea141ef5bc93fcb18e5697f87fec9372ede9085"
|
||||
},
|
||||
"query.log": {
|
||||
"bytes": 443,
|
||||
"sha256": "247d833a9438a0acd61f4a98a587475349033789fed9ed5d7d3eb22ff8a89949"
|
||||
},
|
||||
"initial-failed24.log": {
|
||||
"bytes": 54395,
|
||||
"sha256": "897de362a2d001a83a6880138bc498a28b92602a350ac25405ee38fe81124cc8"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"fmt_exit": 0,
|
||||
"tests_exit": 0,
|
||||
"tests_passed": 5,
|
||||
"generate_exit": 0,
|
||||
"query_exit": 0,
|
||||
"historical_witness_reproduced": true
|
||||
},
|
||||
"commands": [
|
||||
"cargo fmt --all -- --check",
|
||||
"cargo test --locked -p oa-core --example diagram_readability_probe",
|
||||
"cargo run --locked -p oa-core --example diagram_readability_probe -- generate .local/issue38-probe-run01",
|
||||
"cargo run --locked -p oa-core --example diagram_readability_probe -- probe harness/experiments/diagram-readability-20260929/mixed-dispatch-original.json harness/experiments/diagram-readability-20260929/mixed-dispatch-expected-diagnostics.json 00000000-0000-0000-0000-0000000186a1 1982 375 1 .local/issue38-probe-query01.json"
|
||||
],
|
||||
"limits": "Headless full-scene geometry and conservation checks only; no native usability, selection, edit/history/save acceptance or production change."
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
Compiling oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
|
||||
Finished `test` profile [unoptimized] target(s) in 2.39s
|
||||
Running unittests examples\diagram_readability_probe.rs (C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\examples\diagram_readability_probe-6772f474561e0ccd.exe)
|
||||
|
||||
running 5 tests
|
||||
test tests::analytical_query_controls_distinguish_edges_segments_and_labels ... ok
|
||||
test tests::complete_scene_preserves_semantics_sentinel_and_authored_route ... ok
|
||||
test tests::square_port_corner_is_occluded_even_outside_ten_unit_circle ... ok
|
||||
test tests::unexpected_diagnostics_and_invalid_source_fail_closed ... ok
|
||||
test tests::representative_preserves_every_original_record_and_view ... ok
|
||||
|
||||
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.28s
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# Current-router full-scene evidence
|
||||
|
||||
Source `f754ad85d3674a709d10054e6fe23079f977c547` passes formatting, all five
|
||||
probe tests, fixture generation and the separate declared-point query on Windows
|
||||
gnullvm. [Receipt and raw logs](run-f754/receipt.json) bind the executable hash,
|
||||
compiler, commands and artifacts. The original one-pass/four-failure warning
|
||||
admission run remains preserved; [source-derived correction](warning-baseline-review.md)
|
||||
and independent record review establish the exact 60-warning fixture baseline.
|
||||
No model or production validator changed.
|
||||
|
||||
The current router reproduces the historical witness: two real exchanges
|
||||
`...01adb8` and `...01adb9` share a 78-unit run at x1982, y336..414. Query
|
||||
`(1982,375)` at zoom1 finds both at distance zero and no reported node, port,
|
||||
ordinary-label or association-label occluder. Both also retain distinct label
|
||||
and line samples elsewhere. This is point ambiguity, not global inaccessibility.
|
||||
|
||||
Independent read-only review verified all recorded input/source hashes, complete
|
||||
answer-key inventories and Project conservation. The mixed scene has ten nodes
|
||||
and fourteen routes; its authored feedback and sentinel view remain intact. The
|
||||
representative scene has eight nodes and twelve routes; removing its added view
|
||||
recovers the original Project exactly. JSON expansion of an authored f32 `.4`
|
||||
to `.4000000059604645` reflects serialization, not a changed model value.
|
||||
|
||||
The representative contains two unlabeled PortAllocations sharing x1065,
|
||||
y89.5..361, with a ChainInvolvement six world units away. At `(1065,200)` the two
|
||||
PortAllocations are coincident and the ChainInvolvement is at distance6. At
|
||||
`(1065,430)` the latter PortAllocation is at zero and ChainInvolvement at six;
|
||||
`(1071,430)` reverses those distances. The conservative alternate-access probe
|
||||
finds no single-candidate samples for either PortAllocation. Production chooses
|
||||
the nearest segment before selection/identity ties, so this result does not
|
||||
establish native inaccessibility. These are useful distance and tie controls.
|
||||
|
||||
The Technician service conversation's label center is 134.5 units horizontally
|
||||
displaced from its route anchor, providing a local label-association repair case.
|
||||
Native evaluation should first record unaided tracing, then deliberate selection
|
||||
with coincident and distance controls, label/bend repair, cancellation, exact
|
||||
Undo/Redo/save/reopen, and drawing a valid relationship in the populated scene.
|
||||
Inspector lookup does not count as unaided reading. No routing candidate or GUI
|
||||
workflow has been accepted from this headless evidence.
|
||||
@@ -1,31 +0,0 @@
|
||||
# Independent preparatory review
|
||||
|
||||
Read-only review of the new Rust probe, fixed inputs/answer keys, experiment
|
||||
contract and production projection/picking code. No compiler, probe or GUI was
|
||||
run by the reviewer. No remaining source blocker was identified before execution.
|
||||
|
||||
The author addressed these consequential findings:
|
||||
|
||||
- Port-owner mapping adds five valid relationships to the representative view:
|
||||
its complete inventory is twelve, rather than seven. Kind, semantic endpoints,
|
||||
ports, projected endpoints and trace identity are checked independently.
|
||||
- Port occlusion follows the actual square half-width `max(10/zoom, 10)` world
|
||||
units, with a corner control; association-end label rectangles also precede
|
||||
ordinary line picking and are included.
|
||||
- Query candidates count semantic edges separately from their matching segments.
|
||||
Empty ordinary labels do not occlude a point merely because bounds remain.
|
||||
- Historical reproduction requires both declared real identities, zero distance,
|
||||
no occluder and the recorded common span. Declared source provenance requires
|
||||
actual build/fixture verification before a current-router claim.
|
||||
|
||||
Admission, warning baselines and current routing remain execution gates.
|
||||
Two flat scenes cannot establish nested/folded behavior; Traceability removes
|
||||
visual parents. Geometric samples do not establish native selection, readability
|
||||
or global inaccessibility. Read-only Project equality does not verify edit
|
||||
transactions, Undo/Redo or save/reopen. Drawing a new relation requires a separate
|
||||
declared post-change answer key and Project delta.
|
||||
|
||||
The next workflow should trace, deliberately select, repair one label or bend,
|
||||
then undo in the complete scene, with unique labels/unshared spans as controls.
|
||||
Creating a valid relation, refusal and cancellation are separate tasks. A chooser
|
||||
that prints correct endpoints cannot substitute for unaided diagram readability.
|
||||
@@ -1,65 +0,0 @@
|
||||
# Archived warning baseline correction
|
||||
|
||||
The parent compiled source `2aac3e83532166dc45cd3519cc5d89b3e84d57f3` and reported
|
||||
one test passed / four failed at strict admission. The original expected baseline
|
||||
contained 24 warnings. Geometry generation did not run. The failed log remains at
|
||||
`.local/probe-tests-failed24.log`; its SHA256 is recorded in `provenance.json` for later
|
||||
publication by the parent. This correction has not been compiled or executed by
|
||||
the research agent.
|
||||
|
||||
Independent source inspection establishes the following additional 36 warnings.
|
||||
An intermediate, unexecuted 35-warning correction covered system/allocation rules
|
||||
only; independent critique caught the additional 25 typed-port warnings before rerun.
|
||||
No diagnostic output was imported to construct them, and the original model bytes
|
||||
remain unchanged (SHA256 81d25af021cbad18af4262a220ba60372e51ca19083b7e80f2b19196baf05990).
|
||||
|
||||
* `crates/oa-core/src/validation.rs:253–264` warns when any element is SA and no
|
||||
element is a System. The archived model has 10 SA Functions and 25 SA Ports,
|
||||
with no System. Therefore exactly one `missing_system` warning belongs to
|
||||
project `00000000-0000-0000-0000-0000000186a0`, field `elements`, message
|
||||
`Identify the SA system of interest.`
|
||||
* `validation.rs:339–351` warns for each leaf work element with no effective
|
||||
performer. All ten Functions below have no Function child (their own parents
|
||||
are null; any children are Ports). All 14 relations are FunctionalExchanges;
|
||||
there are no Allocations, RoleAssignments, or RoleRealizations. The resolver
|
||||
at `validation.rs:2865–2893` consequently returns no performer for each.
|
||||
Each receives severity `Warning`, code `unallocated_leaf`, field `allocation`,
|
||||
and message `Allocate leaf '<name>' to a performer.` The warning helper at
|
||||
`validation.rs:45–53` retains the supplied element ID and severity.
|
||||
|
||||
| Element ID suffix (prefix `00000000-0000-0000-0000-000000`) | Exact name |
|
||||
| --- | --- |
|
||||
| 018704 | Sensor A |
|
||||
| 018706 | Sensor B |
|
||||
| 018708 | Ingest |
|
||||
| 01870a | Validate |
|
||||
| 01870c | Archive |
|
||||
| 01870e | Correlate |
|
||||
| 018710 | Plan |
|
||||
| 018712 | Dispatch |
|
||||
| 018714 | Actuator |
|
||||
| 018716 | Operator |
|
||||
|
||||
* `crates/oa-core/src/ports.rs:774–815` warns for an empty typed FunctionInput or
|
||||
FunctionOutput item list. All 25 archived Ports have these SA typed contracts:
|
||||
13 FunctionInputs with empty `incoming_items`, and 12 FunctionOutputs with empty
|
||||
`outgoing_items`. Their warning element is the exact Port identity, severity
|
||||
`Warning`, code `empty_port_contract`, field respectively `incoming_items` or
|
||||
`outgoing_items`, and message `This function port has no declared exchange items.`
|
||||
The expected JSON records each identity explicitly. `validation.rs:413` dispatches
|
||||
these elements to the port validator. No generic legacy or component contracts
|
||||
occur, so the separate legacy/orientation warning rules do not apply.
|
||||
|
||||
The complete model inventory is 35 elements (10 Functions and 25 Ports), 14 relations
|
||||
(all FunctionalExchange, with empty carried-item lists), two views, and no traces.
|
||||
There are no sequences, occurrences, states, capabilities, data objects, or other
|
||||
relation families to trigger their specific warning rules. The behavior-context,
|
||||
system, allocation, and typed-port rules exhaust the applicable warning families.
|
||||
|
||||
The existing 24 expected warning records remain intact. The corrected 60-record
|
||||
baseline remains exact: missing, extra, changed-field, changed-message, or error
|
||||
diagnostics still fail. These warnings describe the deliberately incomplete
|
||||
archived synthetic architecture; accepting them as a fixture baseline does not
|
||||
certify architectural completeness. No production rule, probe admission policy,
|
||||
model record, route, or test was weakened. The parent must rerun the tests before
|
||||
claiming successful admission or current-router geometry.
|
||||
@@ -1,6 +0,0 @@
|
||||
native-reading/** -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
|
||||
*.json -text whitespace=cr-at-eol
|
||||
issue38-design-*.md -text whitespace=cr-at-eol
|
||||
launch-reading*.py -text whitespace=cr-at-eol
|
||||
label-candidates/** -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
|
||||
first-exposure/** -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
|
||||
@@ -1,104 +0,0 @@
|
||||
# Full-scene reading and local editing experiment
|
||||
|
||||
This is evidence for [issue 38](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/38),
|
||||
not a production readability fix or full diagram acceptance. The complete
|
||||
eight-card mixed view is a documented reconstruction, not the user's recovered
|
||||
view. Its original semantic inventory and probe source are in the
|
||||
[September 29 experiment](../diagram-readability-20260929/README.md).
|
||||
|
||||
Native desktop source is `6e7c4ddaf0775198384a8c4882809ea8e14b2976`, executable
|
||||
SHA256 `d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e`.
|
||||
Its unchanged routing/core source is the released `715036e` foundation. Geometry
|
||||
queries use probe source `f754ad85d3674a709d10054e6fe23079f977c547`, executable
|
||||
SHA256 `d94f86b2f4af594b27960cfa169fd681adb9b3a5eae2928dd72c541bc2db1c57`.
|
||||
Launch receipts record the exact runtime, system-only child PATH and copied inputs.
|
||||
|
||||
## Observations and conservation
|
||||
|
||||
[Initial reading](native-reading/review.md) records endpoint/path uncertainty.
|
||||
Opening simpler OA/SA views incidentally exposed answers, so it is not pristine
|
||||
blind accuracy evidence. [Assisted inspection](native-reading/assisted/review.md)
|
||||
identifies all three named relations and both distinct port mappings through the
|
||||
actual UI. The conversation label caused a wrong first stroke selection of an
|
||||
ordinary Allocation. Shared-stroke clicks retain the already selected mapping;
|
||||
with no selection they choose one stable mapping. There is no visible chooser or
|
||||
cycling. Both mappings remain reachable through Connections and learned segments;
|
||||
this is ambiguous discovery, not global inaccessibility.
|
||||
|
||||
[Manual editing](native-reading/manual/review.md) predeclares a conversation-label
|
||||
move, then exercises label Undo/Redo and bend add/move/remove with exact restoration.
|
||||
The first native chooser attempt displayed the requested filename but exported to
|
||||
`project.json`; it is preserved as a discrepancy. A second attempt using actual
|
||||
focused typing and Return exports the requested `manual-label.json` with identical
|
||||
bytes. This supports the input-method explanation without proving the first
|
||||
failure's exact cause. JSON export deliberately retains source save state.
|
||||
|
||||
[Independent full-model and geometry review](native-reading/manual/independent-oracle-review.md)
|
||||
confirms the sole stored delta: one label-only route record for `sa_contact`, with
|
||||
empty waypoints and no attachment overrides. All semantic records, ports, six
|
||||
diagrams' other data, 35 placements and original routes remain identical. All 12
|
||||
computed paths and 11 other computed labels are also identical. The displacement
|
||||
is consistent with the recorded mouse gesture and rounded Fit 52%; exact zoom
|
||||
was not independently captured. The review explicitly corrects a transcribed UUID
|
||||
while retaining the original declared record and named intent.
|
||||
|
||||
[Fresh native reopen](native-reading/reopen/review.md) verifies the label's
|
||||
persistence and selection in the complete saved view. Both desktop processes
|
||||
exit 0 with empty logs; pristine input and both exported JSON files retain their
|
||||
pinned bytes. Eight cards are visibly present, while exact relation conservation
|
||||
comes from the model/geometry oracle, not counting coincident strokes visually.
|
||||
Menu Escape cancellation was exercised; mid-drag cancellation remains unverified
|
||||
because the available native tool exposes atomic completed drags.
|
||||
|
||||
## Next experiment and rejection criteria
|
||||
|
||||
[Candidate comparison](issue38-design-candidates.md) evaluates ownership-aware
|
||||
automatic placement, selective unselected association cues and selection-only
|
||||
cues. The [fresh critic](issue38-design-critic.md) finds that the current candidate
|
||||
set has no collision-free placement in this witness; its initial report was an
|
||||
unexecuted double-precision reconstruction. The
|
||||
[restricted Rust confirmation](label-candidates/README.md) now passes all six
|
||||
probe tests, real CLI enumeration, strict example Clippy and byte/model checks.
|
||||
All 184 candidates are evaluated; all six best choices still cross the same
|
||||
foreign Allocation. The retained first test failure was a declared segment-index
|
||||
miscount corrected against the original geometry, with no other assertion changed.
|
||||
This rejects ownership tie-breaking within the fixed existing generator and best
|
||||
collision tuple for the declared nearest-box metric, rather than automatic
|
||||
placement generally. Manual repair intersects both
|
||||
own and foreign strokes and is not a fresh reading success or a validated distance
|
||||
metric. A short boundary-to-anchor cue remains an experiment with explicit noise,
|
||||
shared-anchor, export, cache and first-association rejection gates.
|
||||
|
||||
A separate [fresh first-exposure screenshot review](first-exposure/review.md),
|
||||
without opening-view cues or model lookup, assigns the conversation label to the
|
||||
foreign technician-to-repair Allocation and its arrowhead. Request/report reading
|
||||
remains uncertain. This is one agent's static reading of the actual complete
|
||||
baseline Fit screenshot, not a human study or native interaction acceptance.
|
||||
It corroborates the misassociation independently of the earlier cued reading.
|
||||
|
||||
No production routing or rendering change is accepted here. Direct new-exchange
|
||||
drawing, full shared-corridor readability, broad accessibility/DPI and complete
|
||||
OA/SA acceptance remain outstanding. Authoritative scope and ownership are in
|
||||
Gitea, rather than an additional local live-task ledger.
|
||||
|
||||
## Reproduce the bounded checks
|
||||
|
||||
The [inventory](evidence-files.json) pins the captured files before this README
|
||||
and attributes were authored. Scoped attributes preserve all native snapshot bytes.
|
||||
Copy `native-reading` into a fresh scratch directory before rerunning its Python
|
||||
oracles, which write reports; do not overwrite historical evidence. These helpers
|
||||
are verification glue, not application code. Run `check-manual-geometry.py` on
|
||||
the retained before/after geometry and inspect its precise assertions and limits.
|
||||
|
||||
With the identified probe source and Rust/toolchain environment, reproduce both
|
||||
geometry queries from the repository root, using fresh output filenames:
|
||||
|
||||
```powershell
|
||||
cargo run --locked -p oa-core --example diagram_readability_probe -- probe harness/experiments/diagram-readability-20261001/native-reading/working/eight-card.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 600 450 1 BEFORE.json
|
||||
cargo run --locked -p oa-core --example diagram_readability_probe -- probe harness/experiments/diagram-readability-20261001/native-reading/working/manual-label.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 600 450 1 AFTER.json
|
||||
```
|
||||
|
||||
The captured launchers contain original absolute paths; adapt them to a fresh
|
||||
copied working folder and the exact released binaries. Native reports give the
|
||||
actual pointer, keyboard, selection and chooser sequence. Tool/recording elapsed
|
||||
times are not measured human task times.
|
||||
@@ -1,23 +0,0 @@
|
||||
from pathlib import Path
|
||||
import hashlib,json,subprocess,sys
|
||||
root=Path(subprocess.check_output(['git','rev-parse','--show-toplevel'],text=True).strip())
|
||||
packet=root/sys.argv[1]
|
||||
entries=json.loads((packet/'evidence-files.json').read_text(encoding='utf-8'))
|
||||
names=list(entries)
|
||||
prefix=packet.relative_to(root).as_posix()
|
||||
requests=[':'+prefix+'/'+name for name in names]
|
||||
assert all('\n' not in name for name in requests)
|
||||
stream=subprocess.check_output(['git','cat-file','--batch'],input=('\n'.join(requests)+'\n').encode('utf-8'),cwd=root)
|
||||
offset=0
|
||||
for name in names:
|
||||
end=stream.index(b'\n',offset)
|
||||
header=stream[offset:end].decode('ascii').split()
|
||||
assert len(header)==3 and header[1]=='blob',(name,header)
|
||||
size=int(header[2]);offset=end+1
|
||||
indexed=stream[offset:offset+size];offset+=size
|
||||
assert stream[offset:offset+1]==b'\n';offset+=1
|
||||
data=(packet/name).read_bytes()
|
||||
assert {'bytes':len(data),'sha256':hashlib.sha256(data).hexdigest()}==entries[name],name
|
||||
assert indexed==data,'Indexed snapshot bytes differ: '+name
|
||||
assert offset==len(stream)
|
||||
print(json.dumps({'status':'PASS','captured_files':len(names),'all_indexed_bytes_identical':True},indent=2))
|
||||
@@ -1,298 +0,0 @@
|
||||
{
|
||||
"issue38-design-candidates.md": {
|
||||
"bytes": 9149,
|
||||
"sha256": "9b2f69e2ccab90940bd293d707562745f77f34c2158d9d4c93811f86fc477e37"
|
||||
},
|
||||
"issue38-design-critic.md": {
|
||||
"bytes": 11440,
|
||||
"sha256": "83af5f48985b95f9e573896164e1a01621e2cf21fcfb865f3a53f4b6454e8271"
|
||||
},
|
||||
"launch-reading-reopen.py": {
|
||||
"bytes": 2160,
|
||||
"sha256": "da6292e5183560d75b1aa8dc61de9782bd6d1eb557d4ee141d5ad352f3b0bc74"
|
||||
},
|
||||
"launch-reading.py": {
|
||||
"bytes": 2199,
|
||||
"sha256": "e67c4da095e16d6302a1ea378ac1e60a2567311150b02a11604768e037dc5ed0"
|
||||
},
|
||||
"native-reading/check-manual-geometry.py": {
|
||||
"bytes": 2967,
|
||||
"sha256": "aaf75f040ecb7179787386a28ec279fa06b5975caefc49deb88fb94cd0a34915"
|
||||
},
|
||||
"native-reading/check-manual-label.py": {
|
||||
"bytes": 1412,
|
||||
"sha256": "4bae942d211cc033267024229f8c151d329b04a1ba094abcd6d9f65f4250820e"
|
||||
},
|
||||
"native-reading/finished.json": {
|
||||
"bytes": 886,
|
||||
"sha256": "20ce9c8623978a6d486f42db85a32bc65262b5a64dbf3bffdbd1ef032508631f"
|
||||
},
|
||||
"native-reading/fit-52.png": {
|
||||
"bytes": 151267,
|
||||
"sha256": "6ab503b18cc5425f49f20197cbcee47893cdb47e632506123d50241d8dda07df"
|
||||
},
|
||||
"native-reading/review.md": {
|
||||
"bytes": 6223,
|
||||
"sha256": "0f12f2b06278d9f82b088a5c459ce2aed6de6b1de6ffb6297558f51c1864c70d"
|
||||
},
|
||||
"native-reading/started.json": {
|
||||
"bytes": 742,
|
||||
"sha256": "3c8cab17424dc8b4ab178a6eaa3bc6a5e0e58a8122644b578750047c60fcd095"
|
||||
},
|
||||
"native-reading/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"native-reading/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"native-reading/zoom-62.png": {
|
||||
"bytes": 151470,
|
||||
"sha256": "67b8e0968fdcc2dbb0c25e1a2427b5952a770a000a2980678265027a83306d1a"
|
||||
},
|
||||
"native-reading/assisted/01-request-top.png": {
|
||||
"bytes": 154004,
|
||||
"sha256": "0bce2c90c1e27d140a5bbaa3bfae073e8b588c92b82a667dbef12c3b919899dc"
|
||||
},
|
||||
"native-reading/assisted/02-request-endpoints.png": {
|
||||
"bytes": 157675,
|
||||
"sha256": "a6776b0e4231fb752a1d0758f61b1f2cfae870664fd70fd9b11b358787c1154d"
|
||||
},
|
||||
"native-reading/assisted/03-report-top.png": {
|
||||
"bytes": 153822,
|
||||
"sha256": "5898fb753b78a073b789de2a149173785c2e2514ada27cfc4a9c53921e130f86"
|
||||
},
|
||||
"native-reading/assisted/04-report-endpoints.png": {
|
||||
"bytes": 157567,
|
||||
"sha256": "cb8f995af2032bed50bc6ac89bd40f70b9762948d9c792950a182f898f33a1b0"
|
||||
},
|
||||
"native-reading/assisted/05-conversation-top.png": {
|
||||
"bytes": 153696,
|
||||
"sha256": "fc2e08720a555de644deeaaa128d56397ab2ac4356f75a3c39cda642763bc0ee"
|
||||
},
|
||||
"native-reading/assisted/06-conversation-endpoints.png": {
|
||||
"bytes": 156742,
|
||||
"sha256": "f2867bad5dc2bcdd695369bb6a3c0a94602272e920aeaefc2615451e267c0173"
|
||||
},
|
||||
"native-reading/assisted/07-coincident-stroke-first.png": {
|
||||
"bytes": 152420,
|
||||
"sha256": "921b9c24a9058bc51e1faa9b38214507178c084d390550ceb9d77441685bcdeb"
|
||||
},
|
||||
"native-reading/assisted/08-allocation-connections.png": {
|
||||
"bytes": 142680,
|
||||
"sha256": "d0fb2b3e3152288cde7929ff0b96141595dda08e35a60fa9c8253967cde9827a"
|
||||
},
|
||||
"native-reading/assisted/09-actor-connections.png": {
|
||||
"bytes": 146153,
|
||||
"sha256": "f8df96c231764d8a862e9aaf12c522538667256a53300a797190052b60df08cd"
|
||||
},
|
||||
"native-reading/assisted/10-provider-two-mappings.png": {
|
||||
"bytes": 158635,
|
||||
"sha256": "3a58eaee6a1153551f66ed3e80400e49ecb2e930899c0caae371c77f70a5a689"
|
||||
},
|
||||
"native-reading/assisted/11-report-mapping-selected.png": {
|
||||
"bytes": 137880,
|
||||
"sha256": "1afece8094958e7b11d6cf4807c8f6d1dcd0656ba14972fad5a2507fc39b513c"
|
||||
},
|
||||
"native-reading/assisted/12-report-mapping-identity.png": {
|
||||
"bytes": 150985,
|
||||
"sha256": "e84477ea580cdf8b0c7b612d1bcf8d5582a8a3f187a66b107bee68deb4520d61"
|
||||
},
|
||||
"native-reading/assisted/13-provider-owner.png": {
|
||||
"bytes": 159447,
|
||||
"sha256": "7b823d7bbe9b9f4a7976b8b251b91899e8a2cba0c844b5bf3a502711825ae158"
|
||||
},
|
||||
"native-reading/assisted/14-request-mapping-selected.png": {
|
||||
"bytes": 137688,
|
||||
"sha256": "649c7c966efd7d5e4de960cb3ccfd04fc68eb409ae353e840f6389f554399b83"
|
||||
},
|
||||
"native-reading/assisted/15-request-mapping-identity.png": {
|
||||
"bytes": 150827,
|
||||
"sha256": "f97ac6d30244c16325174a552f31b2939a1dc9c5197c0336f93449e28bf25c07"
|
||||
},
|
||||
"native-reading/assisted/16-cleared-shared-stroke-request.png": {
|
||||
"bytes": 152484,
|
||||
"sha256": "8529c7961aaf4a1d73e5c6f069da9242f8877874ad5670f6ab29107878d91cdb"
|
||||
},
|
||||
"native-reading/assisted/17-lower-stroke-report.png": {
|
||||
"bytes": 152539,
|
||||
"sha256": "2723f8b2548d1d75789a2df7eab0d2759b42dbb6917da6efe141e93ac47102b7"
|
||||
},
|
||||
"native-reading/assisted/18-request-port-owner.png": {
|
||||
"bytes": 157447,
|
||||
"sha256": "3a1efcb8f0b1f77eed3964aad61e95bcdc72d636dcbe9256ede9c4c3c3ef0bda"
|
||||
},
|
||||
"native-reading/assisted/19-report-port-owner.png": {
|
||||
"bytes": 157881,
|
||||
"sha256": "be64ffa1f4ce15210e7f30f291c274fddfc2c56868961823da78e543695d4265"
|
||||
},
|
||||
"native-reading/assisted/20-client-port-owner.png": {
|
||||
"bytes": 158832,
|
||||
"sha256": "d83fc535129eb785ad3dc734a0967e0f844c626f3546f47e0d94ffa29a41ec0e"
|
||||
},
|
||||
"native-reading/assisted/21-request-output-owner.png": {
|
||||
"bytes": 156935,
|
||||
"sha256": "5a9d3bb9efdb8be8325681a687147597a36638aeb506f7abbfe9d8c0f5cd258b"
|
||||
},
|
||||
"native-reading/assisted/22-report-input-owner.png": {
|
||||
"bytes": 157438,
|
||||
"sha256": "3757eadc50f5420fb381de8a2aea2fcb3afc266560c0f0489adce00f9c583397"
|
||||
},
|
||||
"native-reading/assisted/review.md": {
|
||||
"bytes": 9198,
|
||||
"sha256": "ff9a9b2697f15466a12b8150dfd4cd01b24478e5177b9c8d076c6818bd15f7c2"
|
||||
},
|
||||
"native-reading/manual/01-baseline.png": {
|
||||
"bytes": 161792,
|
||||
"sha256": "0f0ad2653d8f579aa38b82775185b82a3433e7a701d7bbdd95dab4db8fb92b95"
|
||||
},
|
||||
"native-reading/manual/02-route-help.png": {
|
||||
"bytes": 242646,
|
||||
"sha256": "2be64e14da0a38c56773b8061fd6316644a9a22f8f73296adc8fde0b64979da0"
|
||||
},
|
||||
"native-reading/manual/03-selected-baseline.png": {
|
||||
"bytes": 152416,
|
||||
"sha256": "a2da288302d4cec09e0974bb91106aaa533b5828a8e06e48c59274b8be5cecea"
|
||||
},
|
||||
"native-reading/manual/04-label-moved.png": {
|
||||
"bytes": 149724,
|
||||
"sha256": "73e498a7dba460ea35f3cd75b67a9117ec921cb510e9c762721a250becb00855"
|
||||
},
|
||||
"native-reading/manual/05-label-undo.png": {
|
||||
"bytes": 148036,
|
||||
"sha256": "b63c1d2106b99ba8d0ccdb3e03dd0840745bcc8bb8f1360549c62f5c1e55d43e"
|
||||
},
|
||||
"native-reading/manual/06-label-redo.png": {
|
||||
"bytes": 148332,
|
||||
"sha256": "03470add72449ce69fc88cc508f2aea5730cbfaa01e6f31edc049b775cfc2b47"
|
||||
},
|
||||
"native-reading/manual/07-route-menu.png": {
|
||||
"bytes": 156885,
|
||||
"sha256": "03c2f87db01874fabe95f0fe3b3d7a293600d2028dd5c0a06b7f1761ea28bcc9"
|
||||
},
|
||||
"native-reading/manual/08-bend-added.png": {
|
||||
"bytes": 148594,
|
||||
"sha256": "b828af8ce0cf82fc6c98dc9088313b3cd50625333f7d165ffe8216e40c5a7d69"
|
||||
},
|
||||
"native-reading/manual/09-bend-moved.png": {
|
||||
"bytes": 149961,
|
||||
"sha256": "49259d46eb81fcbcf2fd5a5a29026756aa84ed94e5893079f5cf876c1fd48ea1"
|
||||
},
|
||||
"native-reading/manual/10-bend-menu.png": {
|
||||
"bytes": 160558,
|
||||
"sha256": "efe7cf4f4db22f3b31e04c6db24f087f38712633bd4c91ebbc53d98b04d4377e"
|
||||
},
|
||||
"native-reading/manual/11-bend-removed.png": {
|
||||
"bytes": 148487,
|
||||
"sha256": "37f49c1b738a8215ebcb8110057c7db6f8c5976b0b40a95fd9a943232c7abb23"
|
||||
},
|
||||
"native-reading/manual/12-remove-undone.png": {
|
||||
"bytes": 147422,
|
||||
"sha256": "f6f56811911f3a3286d59d886249c852c25511c3c1e9f3bdcd776058f546944f"
|
||||
},
|
||||
"native-reading/manual/13-move-undone.png": {
|
||||
"bytes": 147165,
|
||||
"sha256": "78fafe6aacfdf383427c2e5f9a9fd27adf54201b7bc7e7aff2993ffcdf5b3e82"
|
||||
},
|
||||
"native-reading/manual/14-route-restored-label-kept.png": {
|
||||
"bytes": 147092,
|
||||
"sha256": "7b8814dd0061f1b844379205615fe039c5fb7814f35b9d0c96490849a31b78ea"
|
||||
},
|
||||
"native-reading/manual/15-menu-cancelled.png": {
|
||||
"bytes": 146989,
|
||||
"sha256": "4dcbbe0bdefb4b4a18e5a0e0d1762be45b064764314c96d63947997aaea4c390"
|
||||
},
|
||||
"native-reading/manual/16-save-formats.png": {
|
||||
"bytes": 61644,
|
||||
"sha256": "29810a2cf9e097a7cdd7733b8fba0623d43ee3a1ed4dc94ef7fb0e98f1e11612"
|
||||
},
|
||||
"native-reading/manual/17-save-json-path.png": {
|
||||
"bytes": 58079,
|
||||
"sha256": "abc813aabe25def65e138e3e6b96de171f68ba10c2065fef9575f99b9e003b16"
|
||||
},
|
||||
"native-reading/manual/18-export-unexpected-path.png": {
|
||||
"bytes": 151214,
|
||||
"sha256": "86a877d8d0b2d8189425450e48ea65a6481d5694c6347260bb3c48308321c0b9"
|
||||
},
|
||||
"native-reading/manual/19-typed-filename.png": {
|
||||
"bytes": 60453,
|
||||
"sha256": "1139b1ae391a2d0c4b46cb7e43d6b769714f81b546b894bbc2298d61d0a1edd7"
|
||||
},
|
||||
"native-reading/manual/20-correct-export-path.png": {
|
||||
"bytes": 151746,
|
||||
"sha256": "d947e11040a3a4b01746632e4de2ce6107f876db78eacf29321f4cec516054e1"
|
||||
},
|
||||
"native-reading/manual/21-close-prompt.png": {
|
||||
"bytes": 141053,
|
||||
"sha256": "90a5a67be0089bf451a87c84c772141e83354f4b8d9a42e0a2704ea13680a010"
|
||||
},
|
||||
"native-reading/manual/full-diff.json": {
|
||||
"bytes": 569,
|
||||
"sha256": "a471a21fbc1cd7b214dece0274ff91456e643813b8376dd69bf5aed491dd8b7d"
|
||||
},
|
||||
"native-reading/manual/geometry-after.json": {
|
||||
"bytes": 361826,
|
||||
"sha256": "453b8bdbd1c347987c39437ecd532193cb51a787c5dc19125bcacb01e8661592"
|
||||
},
|
||||
"native-reading/manual/geometry-before.json": {
|
||||
"bytes": 360890,
|
||||
"sha256": "497605352c2a746ab1908324016b9bb8b1540e34433449c91135418e7d0e88d8"
|
||||
},
|
||||
"native-reading/manual/geometry-comparison.json": {
|
||||
"bytes": 2260,
|
||||
"sha256": "3cb6c06f2c8ad2ea8bc7c79088b6f77358c8efed899b7d0c09ba15667c6c6fd0"
|
||||
},
|
||||
"native-reading/manual/independent-oracle-review.md": {
|
||||
"bytes": 8656,
|
||||
"sha256": "9b5bd1ce279d711ec83b311d00ad241b3df12ab19318a69e62b8f524c96217dd"
|
||||
},
|
||||
"native-reading/manual/review.md": {
|
||||
"bytes": 10356,
|
||||
"sha256": "30040642465c70edac3febd94c3f0b84954e46e4b8b4a161b5d702845e27a7d4"
|
||||
},
|
||||
"native-reading/manual/second-export-check.json": {
|
||||
"bytes": 192,
|
||||
"sha256": "eadafec0102a9a79689d0667fc578cd0ef91e239673a9ed03eafa0c6f1f6891c"
|
||||
},
|
||||
"native-reading/reopen/01-fit.jpg": {
|
||||
"bytes": 150997,
|
||||
"sha256": "2e1cadb2e27b505183caef34e87d201920530442761dad02e9435dc8d538df5b"
|
||||
},
|
||||
"native-reading/reopen/02-selected.jpg": {
|
||||
"bytes": 153708,
|
||||
"sha256": "50faf5df191b404187a0c3f422ef7c99c6aa8284acbe3d07cf9efc983c410d75"
|
||||
},
|
||||
"native-reading/reopen/finished.json": {
|
||||
"bytes": 864,
|
||||
"sha256": "ec7fe5a4acc2dca7eb0ba2a7c16ecd83374ace32a5a0022bf912ba8000ff8e6a"
|
||||
},
|
||||
"native-reading/reopen/review.md": {
|
||||
"bytes": 3707,
|
||||
"sha256": "5cd02784205bc77cde4405e2f5cea7db4408b719ae3cfaa3ae26236fdbca1903"
|
||||
},
|
||||
"native-reading/reopen/started.json": {
|
||||
"bytes": 721,
|
||||
"sha256": "3cd876d30b1235302bdafa8b36cdc2af0beb0c95ed80842e7876eb28274935c4"
|
||||
},
|
||||
"native-reading/reopen/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"native-reading/reopen/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"native-reading/working/eight-card.json": {
|
||||
"bytes": 138661,
|
||||
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
|
||||
},
|
||||
"native-reading/working/manual-label.json": {
|
||||
"bytes": 138933,
|
||||
"sha256": "39572f8ab176f7b8ac8933a308dcf7b127aa15e3d4f627ef604325a5275812f2"
|
||||
},
|
||||
"native-reading/working/project.json": {
|
||||
"bytes": 138933,
|
||||
"sha256": "39572f8ab176f7b8ac8933a308dcf7b127aa15e3d4f627ef604325a5275812f2"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"review.md": {
|
||||
"bytes": 6334,
|
||||
"sha256": "e3f083690868f6d4514de4baa8b6b5dd4930a34c8b4270df640bd4dbf1d532ab"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
# First-exposure static screenshot reading
|
||||
|
||||
I inspected only `C:/ar-diagram-01a0d717/.local/native-reading/fit-52.png` using `view_image` with `detail: original`. The screenshot is 1442 by 932 pixels. It shows the native Arcadia Studio Architecture page, the view titled “Issue 38 representative eight-card mixed view”, and 52% zoom. I read the working agreement in AGENTS.md but did not inspect source code, model data, answer keys, other reports, comparison images, or external research. The interpretations below are my first readings, recorded before receiving any correctness feedback.
|
||||
|
||||
## Request field repair
|
||||
|
||||
My initial candidate is a directed relation from “Assess pressure alarm” to “Repair valve in the field”, but I cannot confidently establish the first endpoint from this view. Endpoint confidence is low. The label appears just above the horizontal stroke at about y = 611. That stroke runs left to a vertical near x = 430 and right to the closely spaced vertical strokes just left of the repair card. A small open green triangle at the repair card's upper left edge, near y = 591, appears to point toward the card. This suggests a directed arrival at the repair function, with moderate confidence in that local reading.
|
||||
|
||||
The difficult part is establishing which path actually belongs to the label. Following the left vertical upward brings me into the rectangular route above and around “Pressure coordination service”, while other strokes meet or cross near the right edge of “Assess pressure alarm”. Following the right vertical upward brings me toward “Assess an alarm procedure” and the line running toward the actor. I cannot tell reliably whether these are connected branches, crossings, or overlapping independent routes. “Assess an alarm procedure” is therefore a plausible alternative first endpoint; a route involving “Pressure coordination service” is also visually easy to infer. My initial assess-to-repair candidate partly uses the nearby card positions and the label's meaning. It is not a confidently traced endpoint pair.
|
||||
|
||||
## Report repair result
|
||||
|
||||
My initial candidate is a directed relation from “Repair valve in the field” to “Confirm safe pressure”. Endpoint confidence is low to moderate. The label appears above the horizontal stroke at about y = 646. That stroke runs between the repair card's lower left corner and a vertical near x = 521. Following that vertical downward brings me toward the horizontal stroke at y = 797 and an open green triangle pointing into the right edge of “Confirm safe pressure”. This supports the candidate direction toward confirmation.
|
||||
|
||||
However, the small open green triangle at the repair end of the labeled horizontal stroke appears to point left, away from the repair card, and is difficult to distinguish from the other open green card markers. I would tentatively read this as a directional relation, not confidently as an unoriented relation, but the marker convention is not self-explanatory in the screenshot. The same left vertical passes the small arrow at “Reset valve remotely” and intersects the horizontal near y = 568. A reader could therefore follow it to “Reset valve remotely”, or continue upward toward the assessment/service row. I cannot exclude those alternatives from geometry alone. The label meaning makes repair-to-confirmation seem reasonable, but it does not resolve the line ownership.
|
||||
|
||||
## Technician service conversation
|
||||
|
||||
My first reading is a directed relation from “Field technician” to “Repair valve in the field”. Confidence is high relative to the other two readings, and moderate to high overall. A vertical stroke leaves the bottom of the technician card near x = 933, turns left below the label, and then turns down into a small filled arrowhead at the top of the repair card near x = 883. That is a short, locally traceable path. I do not need the label meaning to infer the endpoint pair or downward direction.
|
||||
|
||||
The word “conversation” might suggest an unoriented or two-way relationship in ordinary language, but the visible route has a downward arrowhead. I would follow the visible marker rather than infer two-way semantics from the name. The technician card also has a separate square marker and route at its left edge; I would not assign that route to this label on my first reading.
|
||||
|
||||
## Reading effort and visual ambiguity
|
||||
|
||||
The complete eight-card layout is visible, but the card titles, type captions, and relation labels are very small at 52%. I can decipher the requested labels with concentrated inspection; they are not comfortable scanning text. Several card type captions are substantially harder to read than the card names. Thin grey strokes and very small arrowheads make a route's terminal direction harder to identify than the card structure.
|
||||
|
||||
The largest effort is tracking line identity across the middle of the view. The assessment/service row contains intersections and a route surrounding the service card. Near the repair card, several closely spaced verticals and horizontal turns compete for attention. Near the reset/confirmation cards, one apparent vertical can be followed toward several endpoints. I do not see an unmistakable junction-versus-crossing convention that resolves these alternatives in this image. The first two labels require repeated tracing and still leave uncertainty.
|
||||
|
||||
The blue and purple hollow squares at card boundaries, the green open triangles, and the small filled grey arrowheads appear to be different marker families. Without a visible legend, I cannot confidently separate semantic relation markers from ports or editing affordances. The screenshot says “0 selected”, which argues against treating every coloured boundary marker as a selection handle. The large pointer over Fit and its pale blue highlight look like cursor/UI markings rather than diagram semantics. The dotted canvas and tool buttons also look nonsemantic.
|
||||
|
||||
This is one agent's first-exposure reading of one static screenshot. It is not a human user study, a correctness determination against the underlying model, or acceptance evidence for native gestures, interaction, accessibility, or alternative zoom levels. It establishes only the interpretations and uncertainties observable to this evaluator in this archived Fit view.
|
||||
@@ -1,113 +0,0 @@
|
||||
# Issue 38: unselected label association candidates
|
||||
|
||||
Bounded design proposal, not an accepted implementation. No production changes,
|
||||
grouping, filtering, semantic collapse, or new selection behavior are proposed
|
||||
here. Parent owns synthesis after native evidence. The eight-card arrangement is
|
||||
a representative reconstruction, not the user's recovered view.
|
||||
|
||||
## Evidence and causal hypothesis
|
||||
|
||||
The independent [reading report](native-reading/review.md) recorded uncertainty
|
||||
about the unselected Technician service conversation label. The prior opening
|
||||
views exposed simpler answers, so this is not pristine blind endpoint accuracy.
|
||||
The [assisted report](native-reading/assisted/review.md) nevertheless records an
|
||||
actual wrong first stroke selection: ordinary Allocation to Repair instead of the
|
||||
conversation near its label. Both unlabeled port mappings were then individually
|
||||
reachable through Connections and learned canvas segments. Thus accessible
|
||||
identities do not settle the separate unselected-reading problem.
|
||||
|
||||
The [manual report](native-reading/manual/review.md) demonstrates label dragging
|
||||
and Undo/Redo, and temporary bend editing. Parent's
|
||||
[complete geometry comparison](native-reading/manual/geometry-comparison.json)
|
||||
reports only the target label metadata changed; the Project otherwise and all
|
||||
twelve computed paths remained exact. This demonstrates an existing repair
|
||||
mechanism, not that the repaired placement has passed fresh reading evaluation.
|
||||
|
||||
Inspected implementation:
|
||||
|
||||
- `crates/oa-core/src/routing.rs:612–660` settles paths before labels, incorporates
|
||||
association-end bounds, and retains other cached labels during previews.
|
||||
- `make_label` at 1363 preserves authored label fraction/offset exactly. Automatic
|
||||
candidates use at most 32 fractions and 8 offsets, with an 8192-comparison budget.
|
||||
The initial fraction is .5 and initial offset is (0,-18). It prefers the first
|
||||
zero-collision result and earlier candidates on equal scores.
|
||||
- `label_collisions` at 1483 scores a lexicographic tuple of node overlap count,
|
||||
earlier-label overlap count, and inflated-label/stroke crossing count. It has
|
||||
no ownership-association or foreign-path proximity term. A collision-free
|
||||
candidate is not necessarily associated perceptually with the correct route;
|
||||
bounded search also does not promise a collision-free candidate exists or wins.
|
||||
- `diagram.rs:1303–1370` renders active paths thicker and teal and colors active
|
||||
label text; ordinary labels get white backing. There is no label-to-anchor
|
||||
leader in this rendering block. Label geometry supplies both anchor and center.
|
||||
SVG labels are separately emitted near 2033, so any visual policy needs matching
|
||||
export consideration rather than a canvas-only silent discrepancy.
|
||||
|
||||
Baseline conversation anchor is (1162,274.5), center (1296.5,274.5), label width 233.
|
||||
Its center-to-anchor displacement is 134.5, but its nearest rectangle edge is only
|
||||
18 units from the own vertical route. Therefore **center displacement alone is a
|
||||
bad ambiguity metric**: it mostly measures half the long label's width. A candidate
|
||||
must consider the whole label box, own route, other routes, and visible scale.
|
||||
The independent native wrong association is stronger evidence than a distance
|
||||
threshold picked to fit this one image.
|
||||
|
||||
## Materially different candidates
|
||||
|
||||
| Candidate | Minimal experiment | Benefit and risk |
|
||||
| --- | --- | --- |
|
||||
| A. Automatic placement objective | Keep paths and authored labels exact; evaluate bounded automatic candidates for association with their own route in addition to existing overlap criteria. Initially reuse the current candidate set and budget. Compare an ownership-aware tie-break against a rule rejecting candidates through/closer to unrelated routes when a comparably clear own-route candidate exists. | No extra diagram ink; addresses the cause before selection. Risks: no good candidate in existing set, merely shifting ambiguity, instability under edits/UUID ordering, and conflating long-label width with displacement. Current flattened stroke inputs lack edge identity; ownership-aware scoring needs a deliberate small interface change, not a guessed nearest segment. |
|
||||
| B. Selective unselected association leader | Draw a nonsemantic leader from an ambiguous/displaced label boundary to its existing route anchor, only for labels meeting a declared geometric ambiguity condition. No arrowhead, no endpoint/node connection, no selectable semantic edge, and no stored route edit. | Preserves both authored and automatic label positions and shows association before selection. Risks: more crossings and noise, leaders mistaken for relationships, ambiguous landing on a shared run, screen-space flicker near thresholds, and canvas/SVG divergence. Limit condition must use box/route geometry and ambiguity, not center distance alone. A leader crossing another label/card is a failure, not an acceptable automatic side effect. |
|
||||
| C. Selection-only leader | Add the same association cue only while its label/edge is selected. | Lowest persistent noise; useful during inspection and label repair. It cannot fix the demonstrated first unselected association, because the user must already find the right label/edge. Treat as a complementary repair aid, not acceptance of #38's reading outcome. |
|
||||
|
||||
Candidate A must not weaken the node-overlap priority merely to improve a distance
|
||||
score. Test collision-preserving tie-break first; if it cannot change the failed
|
||||
placement, report that limitation before proposing different priorities or a
|
||||
larger candidate set. Candidate B must visibly differ from semantic paths beyond
|
||||
color (for example a restrained dotted connector without arrows), remain legible
|
||||
at Fit, and avoid port/arrowhead/junction-like endpoint marks. This is a design
|
||||
hypothesis requiring visual testing, not a prescribed final style.
|
||||
|
||||
## Evaluators before iteration
|
||||
|
||||
1. Freeze the full twelve-edge scene, source/build, camera and 52% Fit baseline.
|
||||
Use fresh readers or an unrelated-label variant to remove remembered answers.
|
||||
Before selection/Inspector, ask which path carries the conversation and which
|
||||
participant ports it joins. Record first chosen stroke, confidence, wrong
|
||||
turns, time and zoom/pan. Score text legibility separately from association.
|
||||
2. Repeat on Request/Report (positive controls), the long coincident port corridor,
|
||||
both shorter/longer labels, an intentionally displaced authored label, and a
|
||||
clear close label. A is expected not to move the authored control. B should
|
||||
reveal its association without decorating every ordinary close label.
|
||||
3. Measure per-label own/foreign rectangle-to-path clearance, occlusions, leader
|
||||
intersections if present, and Fit bounds. Do not substitute one weighted score
|
||||
for observed reading. At a shared anchor, a leader that still fails to reveal
|
||||
which distinct route continues is an explicit negative result.
|
||||
4. Require unchanged semantic objects/ports, placements, all authored metadata,
|
||||
and computed paths for pure label-placement/cue trials. Preserve Undo/Redo and
|
||||
save/reopen; derived cues add no history. Label dragging still commits once.
|
||||
Record automatic label settlement after commit rather than promising preview
|
||||
equality. Test UUID reorder and translation variants for order artifacts.
|
||||
5. Bound added work and compare actual scene/preview latency against baseline;
|
||||
avoid rescanning all route pairs every pointer move. Test Fit and working zoom,
|
||||
monochrome/low-color discrimination, and leader visibility against white
|
||||
backing. Count additional visible marks and ask whether users mistake a leader
|
||||
for a relation. Reject improvements requiring hidden edges or missing endpoints.
|
||||
|
||||
## Recommendation and revisit condition
|
||||
|
||||
First prototype **A as a bounded experiment**, because the automatic label is the
|
||||
failure source and manual relocation already demonstrates a geometry-preserving
|
||||
repair. Prefer evidence that a nearby candidate makes the correct association
|
||||
clear without extra strokes. This is not authorization to implement or change
|
||||
the router. Keep B as a materially different comparison, particularly for authored
|
||||
labels A must preserve. Revisit toward B if A cannot improve unselected reading
|
||||
without overlap, excessive search, unstable positions, or regressions elsewhere.
|
||||
Reject C as the sole fix even if assisted lookup becomes easier. Selection
|
||||
disambiguation remains a separate complementary outcome.
|
||||
|
||||
Primary comparison: Sirius explicitly documents an attachment link between an
|
||||
edge and its labels, including different behavior for selected edge versus
|
||||
selected label: [official diagram guide](https://eclipse.dev/sirius/doc/user/diagrams/Diagrams.html).
|
||||
Capella documents local label alignment and layout tools in its
|
||||
[official layout guide](https://github.com/eclipse-capella/capella/blob/master/doc/plugins/org.polarsys.capella.tipsandtricks.doc/html/Tips%20and%20tricks/8_Other%20layout%20facilities/8_Other%20layout%20facilities.mediawiki).
|
||||
These support association and local repair as established workflows; they do not
|
||||
establish that always-visible leaders reduce this scene's cognitive load.
|
||||
@@ -1,63 +0,0 @@
|
||||
# Independent critique: issue 38 label association
|
||||
|
||||
Local-only review at source `971b9721c34e574025144935291944c871ccca16`. Read-only source/geometry/native-report inspection; no compilation, native interaction, production edits, or Gitea actions. Root owns synthesis. The fixture is representative, not the original user view.
|
||||
|
||||
## Decision
|
||||
|
||||
Do not proceed directly from the candidate note to production A. Its proposed first experiment—an ownership-aware tie-break with the existing candidate set and collision priorities—has a concrete feasibility problem in this fixture. Existing candidate geometry cannot give the conversation label a better nearest-rectangle ownership score without changing another premise. First reproduce the bounded enumeration below in the established probe; if confirmed, record A-with-existing-candidates as rejected for this witness. A different candidate generator/objective requires an explicit new experiment, not quiet scope expansion.
|
||||
|
||||
B remains worth a tiny controlled visual comparison because its baseline anchor is on a unique segment and the required leader is short. It is not yet preferred as a solution: it leaves the misleading foreign stroke passing through the label, and a short dotted leader at Fit may be too weak to overcome that cue. C cannot meet the unselected-reading gate.
|
||||
|
||||
## Independently checked geometry
|
||||
|
||||
Sources: `crates/oa-core/src/routing.rs` (Rect, record_segments, route_diagram_impl, make_label, label_collisions); `crates/oa-desktop/src/diagram.rs` (scene cache and drawing); `.local/native-reading/manual/geometry-before.json`, `geometry-comparison.json`; initial/assisted/manual reports and archived `fit-52.png`.
|
||||
|
||||
The conversation is `63009b5f-539e-5914-b630-ec6b7fefb4d5`. Use geometry identity: an earlier native transcription in the assisted report has a different final UUID group. That reporting error does not change the visual evidence.
|
||||
|
||||
- Conversation baseline box: x=1180..1413, y=262.5..286.5; own vertical path x=1162, y=89.5..316.5. Own box/path distance is 18.
|
||||
- Ordinary allocation has a vertical path x=1312.5, y=179..325. It **passes through the conversation box**. Foreign distance is zero. This is stronger than merely being nearby, and the old stroke-collision scorer already detects it.
|
||||
- Manual box after drag: x=1086.845..1319.845, y=204.278..228.278. It intersects BOTH the own vertical stroke and the same foreign allocation. Thus both nearest-box distances become zero. Manual repair proves geometry-preserving editing, but its reported apparent improvement neither validates a nearest-box score nor proves fresh reading success. The foreign stroke now reaches near the label's right edge instead of near its center; box distance discards precisely that distinction.
|
||||
- The source uses a width estimate of seven world units per character plus sixteen, while native text is separately rendered at font size 13. Bounds measure backing/hit geometry, not exact glyph contours. Never present their clearance as a measured human perception threshold.
|
||||
|
||||
### Read-only existing-candidate enumeration
|
||||
|
||||
A JavaScript arithmetic reconstruction over the saved geometry enumerated the exact fraction/offset construction (double precision, no production execution): fractions .5, each path segment midpoint, .05 through .95, ordered by distance from .5 then numeric fraction and deduplicated; 23 fractions times eight offsets = 184 candidates. All eight projected cards have no visual parent, so obstacle rectangles are full card bounds inflated by 12. The 12 routes produce 37 distinct undirected segment geometries after the existing exact-segment deduplication. Earlier labels for the conversation are empty; there are no association end labels in this fixture.
|
||||
|
||||
Checked all candidates, intentionally without budget truncation to give A the strongest possible feasibility case. Candidate/node overlap and inflated-by-three candidate/stroke intersection follow the source's strict orthogonal intersection inequalities; nearest segment/box distances are independently calculated.
|
||||
|
||||
Result: no candidate has zero node overlaps and zero stroke intersections. The minimum for node-clear candidates is one intersected stroke. Exactly these six candidates achieve it:
|
||||
|
||||
| Fraction | Offset | Center y | Own distance | Foreign distance |
|
||||
| --- | --- | ---: | ---: | ---: |
|
||||
| .5 | (134.5, 0) | 274.5 | 18 | 0 |
|
||||
| .45 | (134.5, 0) | 294.8 | 18 | 0 |
|
||||
| .55 | (134.5, 0) | 254.2 | 18 | 0 |
|
||||
| .6 | (134.5, 0) | 233.9 | 18 | 0 |
|
||||
| .65 | (134.5, 0) | 213.6 | 18 | 0 |
|
||||
| segment midpoint, about .676108 | (134.5, 0) | 203 | 18 | 0 |
|
||||
|
||||
Every center x is 1296.5. Every candidate intersects that ordinary allocation. An ownership tie-break can at most change height among these candidates, not resolve the bad owner overlap. Since this enumeration uses double arithmetic and a source reconstruction, it is a falsifiable feasibility finding to confirm with the Rust probe, not a claim of production test execution. The candidates are well away from geometric boundary conditions, making rounding an unlikely reversal.
|
||||
|
||||
## What defeats each proposal
|
||||
|
||||
**A: candidate feasibility and objective semantics.** Collision preservation is not just a protection against regression here: it restricts the winning set to six still-misleading placements. Adding a weighted distance or trying more of the same search cannot fix the absent placement. If a later experiment permits a label backing to cover its own stroke while avoiding foreign strokes, that is a different objective and should be stated and compared explicitly. Do not quietly weaken node/other-label priorities. A global optimization framework, spatial index, or generalized routing API is unnecessary before demonstrating one useful local rule.
|
||||
|
||||
**A: ownership is not one ID per existing Segment.** `record_segments` merges exactly coincident segments and keeps a count; partially overlapping strokes remain separate geometries. Assigning a single owner to the merged segment will falsely treat a shared own/foreign stroke as unique. For the experiment, retain edge-tagged polylines separately from existing route-cost Segment storage; compute ambiguity across distinct semantic edges. Avoid changing routing segment accounting to support label scoring. A long shared run can have own distance zero and foreign distance zero everywhere, so proximity cannot prove identity.
|
||||
|
||||
**A: removing zero-score early exit changes actual cost.** Current scoring exits as soon as (0,0,0) appears, and early-prunes worse candidates. A tie-break that requires finding the best association among all zero-collision candidates loses that exit. If distance work is not charged against the comparison budget, keeping the old 8192 variable does not keep the computational contract. Charge or separately cap all candidate/segment work and expose exhaustion in the experimental report. Never accept an incompletely scored candidate as a better one.
|
||||
|
||||
**A: stable UUID order is repeatability, not invariance.** Both path order and earlier-label precedence depend on UUID. Relabeling UUIDs and recomputing the whole diagram changes paths as well as labels, confounding a label-only evaluation. Run two controls: frozen-path scoring with permuted label order/IDs, and a complete reroute with consistent UUID remapping. Reordering array storage with identical IDs should remain exact. Count all automatically moved labels, even if their stored metadata and paths are unchanged.
|
||||
|
||||
**B: this fixture has a useful but weak testable leader.** Shortest boundary-to-anchor segment is (1180,274.5) to (1162,274.5), length 18, about 9.3 screen pixels at the measured Fit. It reaches a unique own vertical segment without an intervening card/path. That makes it a favorable local leader witness. However, the foreign allocation still passes through the label farther right. A few dots at Fit may disappear or read as another short relationship/branch. A center-to-anchor leader would unnecessarily cross the label backing and should not be used. Any cue must be drawn in an ordering that survives white label backing and later edge strokes; the current loop interleaves individual paths and labels rather than painting all text in one last pass. Match export.
|
||||
|
||||
**B: shared landing and zoom threshold.** A leader to a shared run names no unique route; endpoint markers would add misleading semantics. Reject such a case rather than counting an attachment as success. A threshold based on screen pixels may flicker on zoom and accidentally make camera changes require rescoring all geometry; derive geometry with the scene, keep camera policy simple, and test threshold boundaries. Blanket unselected leaders for every label are not justified.
|
||||
|
||||
**C: circular first-use dependency.** The correct label is already selectable and selection already reveals the full path. Another selected cue may help editing but does not fix the first unselected inference. Accept only as an independently scoped editing aid.
|
||||
|
||||
## Smallest falsifiable next experiments
|
||||
|
||||
1. **Confirm feasibility before implementation.** Extend the existing experimental probe/report, not production routing, to list the current candidates, full old collision tuple, owner-tagged intersection list, own/foreign distance, and actual comparisons consumed. Reproduce the six-candidate result, including baseline. Reject A's existing-set collision-preserving form if it cannot produce a candidate whose owning path is perceptually distinguishable from the allocation. Pure distance improvement is insufficient; a changed height alone is not an automatic pass.
|
||||
2. **Native visual comparison with fixed geometry.** Compare baseline against B's one short boundary leader, plus the already-saved manual label state as an empirical control. The manual state is not a promised good answer. Use a fresh reader or unrelated-label variant; directly open the mixed view; no Inspector before answers. Ask for first chosen path and participant ports, then Request/Report and the two port mappings. Observe both ordinary Fit and working zoom. Record first wrong turn, confidence, tracing time, extra pan/zoom, and whether any cue is mistaken for a semantic relation. Reject a candidate if the original wrong association persists, another relation worsens, cue meaning needs an explanation before it can be used, or complete-scene simultaneous reading is lost. One reader can falsify a design; one success cannot establish broad usability.
|
||||
3. **Only if geometry changes become promising, test settlement and latency.** Preserve full Project and all paths; quantify every derived-label movement after an unrelated edit/Undo, label drag/commit, bend drag/commit, and save/reopen. Cache ordinary hover/selection work: the existing scene cache already avoids rerouting unchanged geometry; route previews freeze other labels, while node/port changes and commit can rebuild. Measure the actual affected rebuild/gesture paths, not a hypothetical reroute on every hover. Compare repeated baseline/candidate timings on both this scene and an existing dense control; reject missed interaction budgets or visible label jumping introduced by the candidate. Establish the latency ceiling from the project's existing performance work, not a newly invented threshold.
|
||||
|
||||
These experiments should precede any release claim. Passing a conversation-label test leaves the other full-view route-branch/shared-corridor reading failures open.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Label candidate confirmation: initial scope
|
||||
|
||||
Bounded issue 38 experiment, delegated by root. Modify only `crates/oa-core/examples/diagram_readability_probe.rs`; parent is sole compiler and integration owner. No production router/renderer changes, GUI, Gitea, commit, or build/test execution by this agent.
|
||||
|
||||
Add read-only `label-candidates INPUT EXPECTED_DIAGNOSTICS DIAGRAM_UUID EDGE_UUID NEW_OUTPUT_JSON` with create-new output. Reconstruct current candidate geometry and full f32 collision scores for flat nodes and simple label context; reject unsupported nested nodes, association-end labels, and earlier nonempty labels. Preserve Project and source bytes. Enumerate an unbudgeted exhaustive superset; do not claim to simulate the production comparison budget or winner.
|
||||
|
||||
Expected falsification witness: 23 fractions times 8 offsets; no node-clear/stroke-clear candidate; six optimum (0,0,1) candidates, all intersecting ordinary `sa_repair_allocation`, own/foreign box clearances 18/0. One fixture test will assert the independently declared expected table with f32 tolerance. Parent will compile and verify actual output before treating findings as confirmed.
|
||||
|
||||
## Implementation ready for parent verification
|
||||
|
||||
Implemented the bounded command in the existing probe and added one representative-fixture falsification test. The report includes each candidate's f32 geometry, full collision tuple, owner-preserving semantic stroke intersections, and uninflated own/foreign box clearances. The command rejects unsupported geometry/label contexts and uses existing diagnostics admission and create-new writing. Existing generate/probe commands and tests remain in place.
|
||||
|
||||
Static review and `git diff --check` completed; no build, formatter, or tests run by this agent. Parent should format the touched Rust file, run the probe's six tests, and execute the new command against the immutable representative input with release1 diagnostics. Expected values are predeclared in the new test; actual Rust output is not yet confirmed.
|
||||
|
||||
Suggested invocation arguments (after the parent's normal build setup):
|
||||
|
||||
```text
|
||||
label-candidates .local/native-reading/working/eight-card.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 63009b5f-539e-5914-b630-ec6b7fefb4d5 NEW_OUTPUT_JSON
|
||||
```
|
||||
|
||||
Source reviewed by author; parent independently owns code/result review. This is not a fresh second critic's implementation review.
|
||||
@@ -1,49 +0,0 @@
|
||||
# Restricted existing-candidate feasibility confirmation
|
||||
|
||||
Executed source `70cf350d23ed3a47ca843754220e4f45fa51aa47`: formatting, all six
|
||||
probe tests, real CLI enumeration and strict example Clippy pass on Windows
|
||||
gnullvm. The first five-pass/one-fail run at `05b1b1d` is retained. Its declared
|
||||
segment index was independently reconciled against the original saved geometry;
|
||||
the entire successor code change is `[2]` to `[1]` in that expectation. No scoring,
|
||||
other expected values or production implementation changed.
|
||||
|
||||
Actual f32 enumeration confirms 184 candidates, zero node-clear/stroke-clear
|
||||
choices, and six best `(0,0,1)` choices. Every best box is 18 world units from its
|
||||
own route and intersects the same foreign ordinary allocation at segment index1.
|
||||
The parent reconciled the complete CLI Project/input bytes and all six owner-tagged
|
||||
winner rows. A second CLI call against its already-existing output fails with
|
||||
AlreadyExists; both input and prior output remain byte-exact. Raw output, gate
|
||||
logs, initial failure, author reconciliation, independent source/arithmetic review,
|
||||
source manifest and parent result remain in this packet.
|
||||
|
||||
This rejects candidate A only as specified: ownership-aware tie-breaking inside
|
||||
the existing generator, preserving the best collision tuple and fixed routes,
|
||||
cannot repair the declared nearest-box ownership metric for this reconstructed
|
||||
view. It does not reject new candidate generators/objectives or automatic layout
|
||||
generally, and does not establish that alternate heights cannot aid perception.
|
||||
The exhaustive probe omits production budgets/early exit; no chooser latency or
|
||||
winner simulation is claimed. Restrictions include flat nodes, an automatic
|
||||
unsuspended nonempty target label, no association-end/earlier nonempty labels,
|
||||
and finite orthogonal paths. The representative view is not recovered user source.
|
||||
Native reading of candidate B remains separate.
|
||||
|
||||
The parent's first direct guard harness omitted the DLL search path and failed
|
||||
its expected-error assertion before capturing a result. A separately retained
|
||||
repeat returns Windows `0xc0000135` with empty streams; this is a startup failure,
|
||||
not a create-new guard pass. The corrected harness explicitly supplies the pinned
|
||||
libunwind directory and system PATH. That actual repeat reaches AlreadyExists.
|
||||
|
||||
From this checkout with Rust configured:
|
||||
|
||||
```powershell
|
||||
cargo fmt --all -- --check
|
||||
cargo test --locked -p oa-core --example diagram_readability_probe
|
||||
cargo clippy --locked -p oa-core --example diagram_readability_probe -- -D warnings
|
||||
cargo run --locked -p oa-core --example diagram_readability_probe -- label-candidates harness/experiments/diagram-readability-20261001/native-reading/working/eight-card.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 63009b5f-539e-5914-b630-ec6b7fefb4d5 NEW_OUTPUT_JSON
|
||||
```
|
||||
|
||||
Choose a nonexistent output path. The collector retains historical absolute paths
|
||||
and performs a deliberate existing-output guard attempt; it is provenance, not a
|
||||
portable replay script. Inventory hashes cover all subpacket files except the
|
||||
inventory itself. Runtime provenance requires the external manifest/source gates;
|
||||
the JSON's embedded experiment description alone is not a build identity.
|
||||
@@ -1,109 +0,0 @@
|
||||
from pathlib import Path
|
||||
import hashlib, json, os, shutil, subprocess
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
source = '70cf350d23ed3a47ca843754220e4f45fa51aa47'
|
||||
assert subprocess.check_output(['git','rev-parse','HEAD'],cwd=root,text=True).strip()==source
|
||||
sha = lambda b: hashlib.sha256(b).hexdigest()
|
||||
load = lambda p: json.loads(p.read_text(encoding='utf-8'))
|
||||
inp = root/'.local/native-reading/working/eight-card.json'
|
||||
output = root/'.local/label-candidates-corrected.json'
|
||||
raw_input = inp.read_bytes(); raw_output = output.read_bytes(); value = load(output)
|
||||
assert sha(raw_input)=='9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
|
||||
assert value['project']==json.loads(raw_input) and value['original_input_utf8']==raw_input.decode('utf-8')
|
||||
assert value['project_conserved'] and value['input_bytes_conserved']
|
||||
assert (value['fraction_count'],value['offset_count'],value['candidate_count'],value['distinct_stroke_count'])==(23,8,184,37)
|
||||
assert value['zero_node_zero_stroke_count']==0 and value['best_collision_tuple']==[0,0,1]
|
||||
winners=[value['candidates'][i] for i in value['best_candidate_indices']]
|
||||
assert len(winners)==6
|
||||
for candidate in winners:
|
||||
assert candidate['own_clearance']==18 and candidate['foreign_clearance']==0
|
||||
assert candidate['own_intersections']==[]
|
||||
assert candidate['foreign_intersections']==[{'edge':'725f2e1b-aa2c-5615-9b1f-28da178168fa','relation_alias':'sa_repair_allocation','segments':[1]}]
|
||||
exe=Path('C:/Users/User/Documents/Git/ARCADIA-Studio/.local/target-gnullvm/debug/examples/diagram_readability_probe.exe')
|
||||
command=[str(exe),'label-candidates',str(inp),str(root/'examples/release1/expected-diagnostics.json'),
|
||||
'00000000-0038-4000-8000-000000000001','63009b5f-539e-5914-b630-ec6b7fefb4d5',str(output)]
|
||||
runtime=Path('C:/ar-compact-01a0d717/.local/package39/bin/libunwind.dll')
|
||||
assert sha(runtime.read_bytes())=='f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4'
|
||||
env=os.environ.copy(); system=os.environ['SystemRoot']
|
||||
env['PATH']=str(runtime.parent)+';'+str(Path(system)/'System32')+';'+system
|
||||
guard=subprocess.run(command,cwd=root,env=env,capture_output=True)
|
||||
assert guard.returncode!=0 and b'AlreadyExists' in guard.stderr
|
||||
assert inp.read_bytes()==raw_input and output.read_bytes()==raw_output
|
||||
packet=root/'harness/experiments/diagram-readability-20261001/label-candidates'
|
||||
packet.mkdir(exist_ok=False)
|
||||
for name in ['label-candidates-first-failed.log','label-candidates-corrected-format.log',
|
||||
'label-candidates-corrected-tests.log','label-candidates-corrected-cli.log',
|
||||
'label-candidates-corrected-clippy.log','label-candidates-corrected.json',
|
||||
'label-candidates-summary.md','label-candidates-independent-review.md',
|
||||
'label-candidates-guard-without-runtime-repeated.json']:
|
||||
shutil.copyfile(root/'.local'/name,packet/name)
|
||||
shutil.copyfile(Path(__file__),packet/'collect-label-candidates.py')
|
||||
source_files=['crates/oa-core/examples/diagram_readability_probe.rs','crates/oa-core/src/routing.rs',
|
||||
'examples/release1/model.json','examples/release1/expected-diagnostics.json',
|
||||
'harness/experiments/diagram-readability-20260929/eight-card-view.json','Cargo.lock']
|
||||
manifest={'source':source,'input_sha256':sha(raw_input),'output_sha256':sha(raw_output),
|
||||
'binary_sha256':sha(exe.read_bytes()),'runtime_sha256':sha(runtime.read_bytes()),'files':{}}
|
||||
for name in source_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')
|
||||
receipt={'status':'PASS','source':source,'candidate_count':184,'best_candidates':winners,
|
||||
'input_bytes_and_complete_project_conserved':True,'existing_output_guard':{
|
||||
'command':command,'exit_code':guard.returncode,'stdout':guard.stdout.decode('utf-8'),
|
||||
'stderr':guard.stderr.decode('utf-8'),'path':env['PATH'],'runtime_sha256':sha(runtime.read_bytes()),'input_unchanged':True,'output_unchanged':True}}
|
||||
(packet/'result.json').write_text(json.dumps(receipt,indent=2)+'\n',encoding='utf-8')
|
||||
(packet/'README.md').write_text('''# Restricted existing-candidate feasibility confirmation
|
||||
|
||||
Executed source `70cf350d23ed3a47ca843754220e4f45fa51aa47`: formatting, all six
|
||||
probe tests, real CLI enumeration and strict example Clippy pass on Windows
|
||||
gnullvm. The first five-pass/one-fail run at `05b1b1d` is retained. Its declared
|
||||
segment index was independently reconciled against the original saved geometry;
|
||||
the entire successor code change is `[2]` to `[1]` in that expectation. No scoring,
|
||||
other expected values or production implementation changed.
|
||||
|
||||
Actual f32 enumeration confirms 184 candidates, zero node-clear/stroke-clear
|
||||
choices, and six best `(0,0,1)` choices. Every best box is 18 world units from its
|
||||
own route and intersects the same foreign ordinary allocation at segment index1.
|
||||
The parent reconciled the complete CLI Project/input bytes and all six owner-tagged
|
||||
winner rows. A second CLI call against its already-existing output fails with
|
||||
AlreadyExists; both input and prior output remain byte-exact. Raw output, gate
|
||||
logs, initial failure, author reconciliation, independent source/arithmetic review,
|
||||
source manifest and parent result remain in this packet.
|
||||
|
||||
This rejects candidate A only as specified: ownership-aware tie-breaking inside
|
||||
the existing generator, preserving the best collision tuple and fixed routes,
|
||||
cannot repair the declared nearest-box ownership metric for this reconstructed
|
||||
view. It does not reject new candidate generators/objectives or automatic layout
|
||||
generally, and does not establish that alternate heights cannot aid perception.
|
||||
The exhaustive probe omits production budgets/early exit; no chooser latency or
|
||||
winner simulation is claimed. Restrictions include flat nodes, an automatic
|
||||
unsuspended nonempty target label, no association-end/earlier nonempty labels,
|
||||
and finite orthogonal paths. The representative view is not recovered user source.
|
||||
Native reading of candidate B remains separate.
|
||||
|
||||
The parent's first direct guard harness omitted the DLL search path and failed
|
||||
its expected-error assertion before capturing a result. A separately retained
|
||||
repeat returns Windows `0xc0000135` with empty streams; this is a startup failure,
|
||||
not a create-new guard pass. The corrected harness explicitly supplies the pinned
|
||||
libunwind directory and system PATH. That actual repeat reaches AlreadyExists.
|
||||
|
||||
From this checkout with Rust configured:
|
||||
|
||||
```powershell
|
||||
cargo fmt --all -- --check
|
||||
cargo test --locked -p oa-core --example diagram_readability_probe
|
||||
cargo clippy --locked -p oa-core --example diagram_readability_probe -- -D warnings
|
||||
cargo run --locked -p oa-core --example diagram_readability_probe -- label-candidates harness/experiments/diagram-readability-20261001/native-reading/working/eight-card.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 63009b5f-539e-5914-b630-ec6b7fefb4d5 NEW_OUTPUT_JSON
|
||||
```
|
||||
|
||||
Choose a nonexistent output path. The collector retains historical absolute paths
|
||||
and performs a deliberate existing-output guard attempt; it is provenance, not a
|
||||
portable replay script. Inventory hashes cover all subpacket files except the
|
||||
inventory itself. Runtime provenance requires the external manifest/source gates;
|
||||
the JSON's embedded experiment description alone is not a build identity.
|
||||
''',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':'PASS','captured_files':len(inventory),'source':source,'output_sha256':sha(raw_output)},indent=2))
|
||||
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"collect-label-candidates.py": {
|
||||
"bytes": 7879,
|
||||
"sha256": "60530ad52007e2cc3b64b376784c902fcf1592a2263cf92357bd999f1e5dd746"
|
||||
},
|
||||
"label-candidates-corrected-cli.log": {
|
||||
"bytes": 476,
|
||||
"sha256": "a0b823c42c4e4bd82cf369c3dcae78505fa926c5859747836245c7b6f56000b2"
|
||||
},
|
||||
"label-candidates-corrected-clippy.log": {
|
||||
"bytes": 131,
|
||||
"sha256": "be3db997064a64f0decf6e32a939325d880930b52570cb1e38e71937ee71ed70"
|
||||
},
|
||||
"label-candidates-corrected-format.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"label-candidates-corrected-tests.log": {
|
||||
"bytes": 923,
|
||||
"sha256": "e992552c7a5ebc47978a8d076fe36025bde7eb96680176b71077fbd13a2e3ab9"
|
||||
},
|
||||
"label-candidates-corrected.json": {
|
||||
"bytes": 546617,
|
||||
"sha256": "3cc6a058fd7b16e1082b0aa38fa322147c129612fa3d27d30e54f7f75e63470b"
|
||||
},
|
||||
"label-candidates-first-failed.log": {
|
||||
"bytes": 1543,
|
||||
"sha256": "75e4759570bf1acc0d0b4eebaa6409d25d068d0877ff9700f7080f6569b92842"
|
||||
},
|
||||
"label-candidates-guard-without-runtime-repeated.json": {
|
||||
"bytes": 90,
|
||||
"sha256": "86e177b1b1018f67cb3554456e8981d664a134528cedbe80fd36a3e6f2030717"
|
||||
},
|
||||
"label-candidates-independent-review.md": {
|
||||
"bytes": 6763,
|
||||
"sha256": "5c5b81a13577b94de6abb18afecede2354103a7d4e1e12def84f6ead4068950b"
|
||||
},
|
||||
"label-candidates-summary.md": {
|
||||
"bytes": 4097,
|
||||
"sha256": "c28c4ea7e90f0abb9898f228234523e30236e8975ae7851dee88aeb37a53dcbc"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 3304,
|
||||
"sha256": "fa6a397d948651be55cce7a5d9eefff653ceb1b4f6411863b3d8c3b45a9eea65"
|
||||
},
|
||||
"result.json": {
|
||||
"bytes": 6398,
|
||||
"sha256": "7d86a5ba5d1ef94d9c2703949d230ed6ae91c17b5f5c5a831538a1a24d6d44fe"
|
||||
},
|
||||
"source-manifest.json": {
|
||||
"bytes": 1419,
|
||||
"sha256": "da54db7e47c7b1bd0ace2fb2a86565ac4b6bcde4f65ad1e7f4cca8c4596ac6c1"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
Compiling oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
|
||||
Finished `dev` profile [unoptimized] target(s) in 1.75s
|
||||
Running `C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\examples\diagram_readability_probe.exe label-candidates .local/native-reading/working/eight-card.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 63009b5f-539e-5914-b630-ec6b7fefb4d5 .local/label-candidates-corrected.json`
|
||||
@@ -1,2 +0,0 @@
|
||||
Checking oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
|
||||
Finished `dev` profile [unoptimized] target(s) in 17.18s
|
||||
@@ -1,14 +0,0 @@
|
||||
Compiling oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
|
||||
Finished `test` profile [unoptimized] target(s) in 33.45s
|
||||
Running unittests examples\diagram_readability_probe.rs (C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\examples\diagram_readability_probe-6772f474561e0ccd.exe)
|
||||
|
||||
running 6 tests
|
||||
test tests::analytical_query_controls_distinguish_edges_segments_and_labels ... ok
|
||||
test tests::complete_scene_preserves_semantics_sentinel_and_authored_route ... ok
|
||||
test tests::square_port_corner_is_occluded_even_outside_ten_unit_circle ... ok
|
||||
test tests::unexpected_diagnostics_and_invalid_source_fail_closed ... ok
|
||||
test tests::conversation_existing_candidates_cannot_avoid_foreign_allocation ... ok
|
||||
test tests::representative_preserves_every_original_record_and_view ... ok
|
||||
|
||||
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.20s
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
Compiling oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
|
||||
Finished `test` profile [unoptimized] target(s) in 1m 26s
|
||||
Running unittests examples\diagram_readability_probe.rs (C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\examples\diagram_readability_probe-6772f474561e0ccd.exe)
|
||||
|
||||
running 6 tests
|
||||
test tests::analytical_query_controls_distinguish_edges_segments_and_labels ... ok
|
||||
test tests::complete_scene_preserves_semantics_sentinel_and_authored_route ... ok
|
||||
test tests::square_port_corner_is_occluded_even_outside_ten_unit_circle ... ok
|
||||
test tests::conversation_existing_candidates_cannot_avoid_foreign_allocation ... FAILED
|
||||
test tests::unexpected_diagnostics_and_invalid_source_fail_closed ... ok
|
||||
test tests::representative_preserves_every_original_record_and_view ... ok
|
||||
|
||||
failures:
|
||||
|
||||
---- tests::conversation_existing_candidates_cannot_avoid_foreign_allocation stdout ----
|
||||
|
||||
thread 'tests::conversation_existing_candidates_cannot_avoid_foreign_allocation' (7848) panicked at crates\oa-core\examples\diagram_readability_probe.rs:731:13:
|
||||
assertion `left == right` failed
|
||||
left: Array [Number(1)]
|
||||
right: Array [Number(2)]
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
||||
|
||||
failures:
|
||||
tests::conversation_existing_candidates_cannot_avoid_foreign_allocation
|
||||
|
||||
test result: FAILED. 5 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.72s
|
||||
|
||||
error: test failed, to rerun pass `-p oa-core --example diagram_readability_probe`
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"returncode": 3221225781,
|
||||
"hex": "0xc0000135",
|
||||
"stdout": "",
|
||||
"stderr": ""
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
# Independent review: restricted label candidate enumeration
|
||||
|
||||
No material source or conceptual defect found in the bounded enumeration. The helper is suitable to test the predeclared geometric feasibility claim. Corrected Rust execution remains a separate parent gate; no passing result is inferred from the earlier five-pass/one-fail run. This review does not accept a production label algorithm or general usability improvement.
|
||||
|
||||
## Exact scope
|
||||
|
||||
Read applicable AGENTS.md, design critic, original production routing implementation, added helper/CLI/test, initial failure and the one-line correction. Source addition: `05b1b1d804c4cd47d9c8ff464644e365d8ede5b2`; corrected assertion commit: `70cf350d23ed3a47ca843754220e4f45fa51aa47`. Current working tree was clean during review.
|
||||
|
||||
Working-file SHA256: `crates/oa-core/examples/diagram_readability_probe.rs` = `cbc6713a4974c77b1c8b44f12cb9e0a2271096bbbdbc883aae0c5ba9703ba483`; `crates/oa-core/src/routing.rs` = `b377fe80cece3892d64f62ba5e1578d8974eeefc2a317620f343a86f2f257fbd`.
|
||||
|
||||
Probe exact SHA256: `cbc6713a4974c77b1c8b44f12cb9e0a2271096bbbdbc883aae0c5ba9703ba483`.
|
||||
|
||||
No compiler, GUI, Gitea, commit or production edit. Read-only Python arithmetic independently reconstructed candidate geometry over previously captured baseline paths. This report is the only new artifact.
|
||||
|
||||
## Production correspondence
|
||||
|
||||
`LabelProbeRect` matches production rectangle construction, inflation, strict overlap and strict segment-intersection inequalities including EPSILON 0.001. Under the required exact orthogonality, its interval-separation/hypot clearance is the segment-to-uninflated-box distance, not a perceptual or glyph distance.
|
||||
|
||||
The flat-node guard makes all production traversable-ancestor sets empty, so full node rectangles inflated by 12 reproduce edge_obstacles. No association-end labels and no earlier nonempty ordinary labels imply the production prior-label collision component is exactly zero. Authored target labels and suspended custom routes are rejected. Unknown diagram/edge, empty label, too-short path, nonfinite or nonorthogonal paths and changed label dimensions are rejected rather than silently approximated.
|
||||
|
||||
Fraction generation matches production f32 length accumulation, segment midpoints, 1/20 increments, sorting by distance from 0.5 then numeric order, exact deduplication and truncation at 32. Eight offsets and label width/height reconstruction match. Anchor interpolation calls the actual production point_along_polyline helper. Final candidate bounds use the same f32 expression order.
|
||||
|
||||
Distinct nonzero strokes are deduplicated only by exact undirected endpoint equality, matching record_segments. Production label collision score counts each stored segment once and does not multiply by its multiplicity. The probe does the same; it separately walks original edge-tagged segment windows to retain every semantic owner and zero-based segment index. It therefore does not collapse coincident foreign ownership into the target's identity. Partially overlapping segments stay distinct in both paths.
|
||||
|
||||
The helper intentionally computes full tuples without the 8192 budget, early pruning or early successful exit. It enumerates the complete generator set, a superset of candidates actually examined by the production chooser. This is appropriate for proving absence within that set; it does not reproduce the actual chooser's work count, budget exhaustion, winner or latency. The report states that boundary.
|
||||
|
||||
## Independent witness reconciliation
|
||||
|
||||
Independent read-only arithmetic over the original geometry-before.json, with explicit f32 rounding of candidate/interpolation operations, reproduces 23 fractions, 184 candidates, 37 distinct strokes, minimum tuple (0,0,1), and precisely the declared six best fractions: 0.5, approximately 0.45/0.55/0.6/0.65/0.67610836. All use offset (134.5,0), center x1296.5 and the predeclared center y values within f32 tolerance. Their boxes remain 18 units from the own path and intersect the foreign allocation. This is independent arithmetic confirmation, not Rust test execution.
|
||||
|
||||
The first failed Rust log is preserved with SHA256 `75e4759570bf1acc0d0b4eebaa6409d25d068d0877ff9700f7080f6569b92842`. Its failed assertion was declared segment [2] versus actual [1]. The original captured allocation points are (1312.5,161), (1312.5,179), (1312.5,325), (1216,325), (1216,343). The offending vertical is therefore windows(2) index 1; index 2 is horizontal. Independent geometry supports correcting only [2] to [1]. Git confirms that is the entire successor change. The failed run stopped in the first winner row, so it does not establish successful completion of all six rows.
|
||||
|
||||
## Preservation and limits
|
||||
|
||||
The CLI uses existing exact-diagnostics admission, rejects model errors or changed warning sets, reads input bytes, retains original UTF-8 text in output, compares input bytes again after analysis, and writes through create_new. Existing outputs or output equal to input fail without replacement. Project is immutable to the helper and explicitly compared to its clone. These are read-only/single-writer experiment checks, not a filesystem lock or atomic cross-process promise. Create-new output can remain partial on a later write failure; failed attempts should stay identifiable.
|
||||
|
||||
The new test checks independently declared full-model preservation, candidate/stroke counts, absence of a zero-node/zero-stroke option, exact optimum tuple, all six expected best placements, ownership/alias/segment and clearance values. Unsupported-context rejection and create-new behavior are not newly exercised by this test. Source inspection supports them; do not turn this into a generic nested/association/earlier-label scorer without separate work.
|
||||
|
||||
The defensible conclusion after corrected execution is narrow: on these fixed representative paths, no existing generator candidate can improve the declared own-versus-foreign nearest-box relationship while preserving the best collision tuple. All six best candidates still intersect the same allocation. This does not prove every change in height is perceptually useless, all automatic placement strategies are impossible, a different candidate generator is unnecessary, or that the manual control/B cue improves fresh reading. Those require separately declared metrics and native evidence. The representative view remains a reconstruction, not recovered user source.
|
||||
|
||||
No material finding requires production changes. Before recording A's restricted metric formulation as rejected, retain the corrected Rust result/output, complete input/source identity and this explicit scope. Production budgets/performance and B native acceptance remain outside this review.
|
||||
@@ -1,39 +0,0 @@
|
||||
# Label candidate confirmation: initial scope
|
||||
|
||||
Bounded issue 38 experiment, delegated by root. Modify only `crates/oa-core/examples/diagram_readability_probe.rs`; parent is sole compiler and integration owner. No production router/renderer changes, GUI, Gitea, commit, or build/test execution by this agent.
|
||||
|
||||
Add read-only `label-candidates INPUT EXPECTED_DIAGNOSTICS DIAGRAM_UUID EDGE_UUID NEW_OUTPUT_JSON` with create-new output. Reconstruct current candidate geometry and full f32 collision scores for flat nodes and simple label context; reject unsupported nested nodes, association-end labels, and earlier nonempty labels. Preserve Project and source bytes. Enumerate an unbudgeted exhaustive superset; do not claim to simulate the production comparison budget or winner.
|
||||
|
||||
Expected falsification witness: 23 fractions times 8 offsets; no node-clear/stroke-clear candidate; six optimum (0,0,1) candidates, all intersecting ordinary `sa_repair_allocation`, own/foreign box clearances 18/0. One fixture test will assert the independently declared expected table with f32 tolerance. Parent will compile and verify actual output before treating findings as confirmed.
|
||||
|
||||
## Implementation ready for parent verification
|
||||
|
||||
Implemented the bounded command in the existing probe and added one representative-fixture falsification test. The report includes each candidate's f32 geometry, full collision tuple, owner-preserving semantic stroke intersections, and uninflated own/foreign box clearances. The command rejects unsupported geometry/label contexts and uses existing diagnostics admission and create-new writing. Existing generate/probe commands and tests remain in place.
|
||||
|
||||
Static review and `git diff --check` completed; no build, formatter, or tests run by this agent. Parent should format the touched Rust file, run the probe's six tests, and execute the new command against the immutable representative input with release1 diagnostics. Expected values are predeclared in the new test; actual Rust output is not yet confirmed.
|
||||
|
||||
Suggested invocation arguments (after the parent's normal build setup):
|
||||
|
||||
```text
|
||||
label-candidates .local/native-reading/working/eight-card.json examples/release1/expected-diagnostics.json 00000000-0038-4000-8000-000000000001 63009b5f-539e-5914-b630-ec6b7fefb4d5 NEW_OUTPUT_JSON
|
||||
```
|
||||
|
||||
Source reviewed by author; parent independently owns code/result review. This is not a fresh second critic's implementation review.
|
||||
|
||||
## First Rust run: declared segment-index transcription correction
|
||||
|
||||
Parent's first six-test run at frozen source `05b1b1d804c4cd47d9c8ff464644e365d8ede5b2` failed: five tests passed and the new fixture test stopped at its first-row segment-index assertion (actual `[1]`, declared `[2]`). Preserve `.local/label-candidates-tests.log` as failure evidence. Counts, optimum tuple, and first-row geometry/ownership assertions had passed before that point; the complete six-row finding remains pending the corrected run.
|
||||
|
||||
Independently reopened the original saved baseline `.local/native-reading/manual/geometry-before.json`, not the new Rust output. Ordinary allocation `725f2e1b-aa2c-5615-9b1f-28da178168fa` has these consecutive points:
|
||||
|
||||
```text
|
||||
0: (1312.5,161)
|
||||
1: (1312.5,179)
|
||||
2: (1312.5,325)
|
||||
3: (1216,325)
|
||||
4: (1216,343)
|
||||
```
|
||||
|
||||
Thus the vertical segment at x1312.5, y179..325 is zero-based window index **1**; index 2 is the horizontal segment at y325. The probe reports `edge.points.windows(2).enumerate()` indices, with no segment merging in its semantic owner lists. Production `record_segments` deduplication affects the independent collision tuple only, not these semantic indices. The candidate baseline box y262.5..286.5 intersects index 1 and cannot intersect horizontal index 2 even after its 3-unit inflation.
|
||||
|
||||
The `[2]` assertion was my declared index miscount, contradicted by the pre-existing geometry; it was not evidence of changed routing. Corrected only `[2]` to `[1]` in that assertion. No other expected value, tolerance, geometry rule, or assumption changed. No compile, test execution, GUI, commit, or Gitea action by this agent.
|
||||
@@ -1,278 +0,0 @@
|
||||
{
|
||||
"status": "PASS",
|
||||
"source": "70cf350d23ed3a47ca843754220e4f45fa51aa47",
|
||||
"candidate_count": 184,
|
||||
"best_candidates": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1162.0,
|
||||
"y": 274.5
|
||||
},
|
||||
"bounds": {
|
||||
"position": {
|
||||
"x": 1180.0,
|
||||
"y": 262.5
|
||||
},
|
||||
"size": {
|
||||
"height": 24.0,
|
||||
"width": 233.0
|
||||
}
|
||||
},
|
||||
"center": {
|
||||
"x": 1296.5,
|
||||
"y": 274.5
|
||||
},
|
||||
"collision_tuple": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"foreign_clearance": 0.0,
|
||||
"foreign_intersections": [
|
||||
{
|
||||
"edge": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"relation_alias": "sa_repair_allocation",
|
||||
"segments": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"fraction": 0.5,
|
||||
"offset": {
|
||||
"x": 134.5,
|
||||
"y": 0.0
|
||||
},
|
||||
"own_clearance": 18.0,
|
||||
"own_intersections": []
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1162.0,
|
||||
"y": 294.79998779296875
|
||||
},
|
||||
"bounds": {
|
||||
"position": {
|
||||
"x": 1180.0,
|
||||
"y": 282.79998779296875
|
||||
},
|
||||
"size": {
|
||||
"height": 24.0,
|
||||
"width": 233.0
|
||||
}
|
||||
},
|
||||
"center": {
|
||||
"x": 1296.5,
|
||||
"y": 294.79998779296875
|
||||
},
|
||||
"collision_tuple": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"foreign_clearance": 0.0,
|
||||
"foreign_intersections": [
|
||||
{
|
||||
"edge": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"relation_alias": "sa_repair_allocation",
|
||||
"segments": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"fraction": 0.44999998807907104,
|
||||
"offset": {
|
||||
"x": 134.5,
|
||||
"y": 0.0
|
||||
},
|
||||
"own_clearance": 18.0,
|
||||
"own_intersections": []
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1162.0,
|
||||
"y": 254.1999969482422
|
||||
},
|
||||
"bounds": {
|
||||
"position": {
|
||||
"x": 1180.0,
|
||||
"y": 242.1999969482422
|
||||
},
|
||||
"size": {
|
||||
"height": 24.0,
|
||||
"width": 233.0
|
||||
}
|
||||
},
|
||||
"center": {
|
||||
"x": 1296.5,
|
||||
"y": 254.1999969482422
|
||||
},
|
||||
"collision_tuple": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"foreign_clearance": 0.0,
|
||||
"foreign_intersections": [
|
||||
{
|
||||
"edge": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"relation_alias": "sa_repair_allocation",
|
||||
"segments": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"fraction": 0.550000011920929,
|
||||
"offset": {
|
||||
"x": 134.5,
|
||||
"y": 0.0
|
||||
},
|
||||
"own_clearance": 18.0,
|
||||
"own_intersections": []
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1162.0,
|
||||
"y": 233.89999389648438
|
||||
},
|
||||
"bounds": {
|
||||
"position": {
|
||||
"x": 1180.0,
|
||||
"y": 221.89999389648438
|
||||
},
|
||||
"size": {
|
||||
"height": 24.0,
|
||||
"width": 233.0
|
||||
}
|
||||
},
|
||||
"center": {
|
||||
"x": 1296.5,
|
||||
"y": 233.89999389648438
|
||||
},
|
||||
"collision_tuple": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"foreign_clearance": 0.0,
|
||||
"foreign_intersections": [
|
||||
{
|
||||
"edge": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"relation_alias": "sa_repair_allocation",
|
||||
"segments": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"fraction": 0.6000000238418579,
|
||||
"offset": {
|
||||
"x": 134.5,
|
||||
"y": 0.0
|
||||
},
|
||||
"own_clearance": 18.0,
|
||||
"own_intersections": []
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1162.0,
|
||||
"y": 213.60000610351562
|
||||
},
|
||||
"bounds": {
|
||||
"position": {
|
||||
"x": 1180.0,
|
||||
"y": 201.60000610351562
|
||||
},
|
||||
"size": {
|
||||
"height": 24.0,
|
||||
"width": 233.0
|
||||
}
|
||||
},
|
||||
"center": {
|
||||
"x": 1296.5,
|
||||
"y": 213.60000610351562
|
||||
},
|
||||
"collision_tuple": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"foreign_clearance": 0.0,
|
||||
"foreign_intersections": [
|
||||
{
|
||||
"edge": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"relation_alias": "sa_repair_allocation",
|
||||
"segments": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"fraction": 0.6499999761581421,
|
||||
"offset": {
|
||||
"x": 134.5,
|
||||
"y": 0.0
|
||||
},
|
||||
"own_clearance": 18.0,
|
||||
"own_intersections": []
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1162.0,
|
||||
"y": 203.0
|
||||
},
|
||||
"bounds": {
|
||||
"position": {
|
||||
"x": 1180.0,
|
||||
"y": 191.0
|
||||
},
|
||||
"size": {
|
||||
"height": 24.0,
|
||||
"width": 233.0
|
||||
}
|
||||
},
|
||||
"center": {
|
||||
"x": 1296.5,
|
||||
"y": 203.0
|
||||
},
|
||||
"collision_tuple": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"foreign_clearance": 0.0,
|
||||
"foreign_intersections": [
|
||||
{
|
||||
"edge": "725f2e1b-aa2c-5615-9b1f-28da178168fa",
|
||||
"relation_alias": "sa_repair_allocation",
|
||||
"segments": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"fraction": 0.6761083602905273,
|
||||
"offset": {
|
||||
"x": 134.5,
|
||||
"y": 0.0
|
||||
},
|
||||
"own_clearance": 18.0,
|
||||
"own_intersections": []
|
||||
}
|
||||
],
|
||||
"input_bytes_and_complete_project_conserved": true,
|
||||
"existing_output_guard": {
|
||||
"command": [
|
||||
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\target-gnullvm\\debug\\examples\\diagram_readability_probe.exe",
|
||||
"label-candidates",
|
||||
"C:\\ar-diagram-01a0d717\\.local\\native-reading\\working\\eight-card.json",
|
||||
"C:\\ar-diagram-01a0d717\\examples\\release1\\expected-diagnostics.json",
|
||||
"00000000-0038-4000-8000-000000000001",
|
||||
"63009b5f-539e-5914-b630-ec6b7fefb4d5",
|
||||
"C:\\ar-diagram-01a0d717\\.local\\label-candidates-corrected.json"
|
||||
],
|
||||
"exit_code": 1,
|
||||
"stdout": "",
|
||||
"stderr": "Error: Os { code: 80, kind: AlreadyExists, message: \"The file exists.\" }\n",
|
||||
"path": "C:\\ar-compact-01a0d717\\.local\\package39\\bin;C:\\Windows\\System32;C:\\Windows",
|
||||
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
|
||||
"input_unchanged": true,
|
||||
"output_unchanged": true
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"source": "70cf350d23ed3a47ca843754220e4f45fa51aa47",
|
||||
"input_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
|
||||
"output_sha256": "3cc6a058fd7b16e1082b0aa38fa322147c129612fa3d27d30e54f7f75e63470b",
|
||||
"binary_sha256": "9e07a8cf703c1c3247d2b6f9bc63468fd4ad902f49f0a13b290104177db5230a",
|
||||
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
|
||||
"files": {
|
||||
"crates/oa-core/examples/diagram_readability_probe.rs": {
|
||||
"bytes": 36267,
|
||||
"sha256": "cbc6713a4974c77b1c8b44f12cb9e0a2271096bbbdbc883aae0c5ba9703ba483"
|
||||
},
|
||||
"crates/oa-core/src/routing.rs": {
|
||||
"bytes": 53958,
|
||||
"sha256": "b377fe80cece3892d64f62ba5e1578d8974eeefc2a317620f343a86f2f257fbd"
|
||||
},
|
||||
"examples/release1/model.json": {
|
||||
"bytes": 134520,
|
||||
"sha256": "ef0ef4006c3e09d5db6e1b621256b3f7d6642f3a7b09cc34607cfbcca830c727"
|
||||
},
|
||||
"examples/release1/expected-diagnostics.json": {
|
||||
"bytes": 288,
|
||||
"sha256": "3700393d76b940cfc076bf52861bd7b1f43370f8eabce3594531bd0bf1fc851e"
|
||||
},
|
||||
"harness/experiments/diagram-readability-20260929/eight-card-view.json": {
|
||||
"bytes": 3641,
|
||||
"sha256": "f851e7e96fc6f5b1edb328b94eb991aa8e94b14cc1bcd07b2c42d32310c4527b"
|
||||
},
|
||||
"Cargo.lock": {
|
||||
"bytes": 119855,
|
||||
"sha256": "2aa80d113c5112b31c0767b874845d60f555e4e8ae7eb3ecd0b4b91954b55378"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
from pathlib import Path
|
||||
import datetime,hashlib,json,os,subprocess
|
||||
root=Path('C:/ar-diagram-01a0d717');reading=root/'.local/native-reading'
|
||||
run=reading/'reopen';run.mkdir(exist_ok=False)
|
||||
work=reading/'working'
|
||||
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
baseline={p.name:sha(p) for p in work.glob('*.json')}
|
||||
assert baseline['manual-label.json']==baseline['project.json']=='39572f8ab176f7b8ac8933a308dcf7b127aa15e3d4f627ef604325a5275812f2'
|
||||
assert baseline['eight-card.json']=='9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
|
||||
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'
|
||||
assert sha(exe)=='d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e'
|
||||
env=os.environ.copy();system=os.environ['SystemRoot'];env['PATH']=str(Path(system)/'System32')+';'+system
|
||||
for k in list(env):
|
||||
if k.startswith(('CARGO_','RUST','LLVM','WGPU','ARCADIA_')):del env[k]
|
||||
receipt={'source':'6e7c4ddaf0775198384a8c4882809ea8e14b2976','start':datetime.datetime.now(datetime.timezone.utc).isoformat(),'binary_sha256':sha(exe),'runtime_sha256':sha(bundle/'libunwind.dll'),'input_files':baseline,'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,'inputs_unchanged':{p.name:sha(p) for p in work.glob('*.json')}==baseline})
|
||||
(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['inputs_unchanged']
|
||||
@@ -1,23 +0,0 @@
|
||||
from pathlib import Path
|
||||
import datetime,hashlib,json,os,shutil,subprocess
|
||||
root=Path('C:/ar-diagram-01a0d717')
|
||||
run=root/'.local/native-reading';run.mkdir(exist_ok=False)
|
||||
work=run/'working';work.mkdir()
|
||||
fixture=root/'.local/issue38-probe-run01/eight-card-representative.json'
|
||||
shutil.copyfile(fixture,work/'eight-card.json')
|
||||
baseline=hashlib.sha256(fixture.read_bytes()).hexdigest()
|
||||
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'
|
||||
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
assert sha(exe)=='d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e'
|
||||
env=os.environ.copy();system=os.environ['SystemRoot'];env['PATH']=str(Path(system)/'System32')+';'+system
|
||||
for k in list(env):
|
||||
if k.startswith(('CARGO_','RUST','LLVM','WGPU','ARCADIA_')):del env[k]
|
||||
receipt={'source':'6e7c4ddaf0775198384a8c4882809ea8e14b2976','routing_core_source':'715036e132677dd2bc2fb37ed316d93dc9987aec','fixture_probe_source':'f754ad85d3674a709d10054e6fe23079f977c547','start':datetime.datetime.now(datetime.timezone.utc).isoformat(),'binary_sha256':sha(exe),'runtime_sha256':sha(bundle/'libunwind.dll'),'fixture_sha256':baseline,'fixture':str(work/'eight-card.json'),'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')==baseline})
|
||||
(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['fixture_unchanged']
|
||||
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 149 KiB |