Compare commits

...
122 changed files with 62524 additions and 14 deletions
@@ -0,0 +1,881 @@
//! 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));
}
}
@@ -1,6 +1,7 @@
use super::*;
use crate::app::multiselect::{self, Choice};
use crate::diagram_usage::Target as SelectionTarget;
use iced::widget::text_editor;
#[path = "group/connection_lifetime.rs"]
mod connection_lifetime;
@@ -10,6 +10,11 @@ async fn press_escape(mounted: &mut Mounted, app: &mut App) -> Vec<Message> {
std::slice::from_ref(&input),
mouse::Cursor::Unavailable,
);
assert_eq!(
statuses,
[iced::event::Status::Captured],
"the mounted picker must capture Escape before App subscriptions"
);
crate::app::escape::tests::subscriptions(app, input, statuses[0], &mut messages);
for message in messages.iter().cloned() {
let task = app.update(message);
@@ -41,17 +46,11 @@ async fn mounted_state_missing_picker_escape_preserves_exact_document_then_reope
send(&mut app, Message::BehaviorDiagram(choice));
let mut mounted = Mounted::new(&mut app).await;
assert_eq!(state_edit::unplaced(app.project(), diagram), vec![f.b]);
let focus_id = iced::advanced::widget::Id::from("diagram-keyboard-owner");
let (_, canvas, _) = mounted
.geometry(&app)
.focused
.into_iter()
.find(|(id, _, _)| id.as_ref() == Some(&focus_id))
.unwrap();
// The existing picker is immediately above the measured canvas, separated
// by 8px. Its 12px text and 8px padding give a 31.6px row.
let picker = iced::Point::new(canvas.center_x(), canvas.y - 24.);
let option = iced::Point::new(picker.x, canvas.y + 8.);
// Locate the stable picker slot itself: selection controls may sit between
// it and the canvas. The single menu option opens below this slot.
let bounds = mounted.geometry(&app).bounds("state-missing-picker");
let picker = bounds.center();
let option = iced::Point::new(picker.x, bounds.y + bounds.height * 1.5);
let before = app.document.snapshot();
let original = app.project().clone();
let source = app.document.bundle().clone();
+1 -1
View File
@@ -187,7 +187,7 @@ pub fn view<'a>(app: &'a App, machine: Id, mut out: Column<'a, Message>) -> Elem
.into();
out = out.push(
column![
missing_controls,
container(missing_controls).id("state-missing-picker"),
selection_controls(app),
crate::diagram::focus::wrap(
canvas.map(event),
+12 -2
View File
@@ -9,7 +9,8 @@ excluded by the user's explicit request, including after networking recovers.**
## Assembled source and acceptance boundary
Combined code **4deced53b98cd4d7649ba7aa60fa4b9b30d2f3b8** adds the reviewed
Combined code through **4deced53b98cd4d7649ba7aa60fa4b9b30d2f3b8**, plus the
test-only import correction from **7c2b06b63f8a0fe14b3f001996bdf965b36a4e85**, adds the reviewed
Connection/Route early-admission correction to the assembled Scenario/Text,
ordinary/State/Process/Allocation selection, direct drawing, Traceability and
picker changes. The [source handoff](prerelease-integrated-source-20260924.md)
@@ -21,7 +22,16 @@ claim combined Cargo, native, packaged or release acceptance. The independent
further material source defect in its stated scope. A subsequent peer compile
found a missing `projection::` qualification in the new Route test helper;
the current code includes that one-line correction. The original compile failed
before running tests. Combined execution remains pending.
before running tests. The first combined compile at `897d9f04` subsequently
found a missing `text_editor` import in the Allocation Text Apply regression;
the current source includes that one-line correction too. Both failures remain
recorded in the source handoff. The subsequent full test run at `8ddfadf4`
failed the mounted State picker fixture: added selection controls invalidated
its canvas-relative clicks. Source successor `a9cd364eacbbffa0693bab05b5a2b65f9d105535`
measures an identified fixed-height picker slot and checks Escape capture,
retaining the exact preservation/reopen/Place/Undo assertions. The source
handoff links the preserved failed and interrupted attempts. Corrected combined
Windows execution and package acceptance remain pending.
Live build, final-source and publication results belong in
[issue37](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/37).
+49
View File
@@ -0,0 +1,49 @@
# 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,3 @@
# 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
@@ -0,0 +1,115 @@
# 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.
@@ -0,0 +1,134 @@
[
{
"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
}
]
@@ -0,0 +1,132 @@
{
"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"
}
}
@@ -0,0 +1,156 @@
[
{
"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
}
]
@@ -0,0 +1,422 @@
[
{
"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."
}
]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,103 @@
{
"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."
}
@@ -0,0 +1,3 @@
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`
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
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`
@@ -0,0 +1,60 @@
{
"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."
}
@@ -0,0 +1,13 @@
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
@@ -0,0 +1,39 @@
# 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.
@@ -0,0 +1,31 @@
# 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.
@@ -0,0 +1,65 @@
# 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.
@@ -0,0 +1,6 @@
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
@@ -0,0 +1,104 @@
# 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.
@@ -0,0 +1,23 @@
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))
@@ -0,0 +1,298 @@
{
"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"
}
}
@@ -0,0 +1,6 @@
{
"review.md": {
"bytes": 6334,
"sha256": "e3f083690868f6d4514de4baa8b6b5dd4930a34c8b4270df640bd4dbf1d532ab"
}
}
@@ -0,0 +1,31 @@
# 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.
@@ -0,0 +1,113 @@
# 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.
@@ -0,0 +1,63 @@
# 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.
@@ -0,0 +1,21 @@
# 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.
@@ -0,0 +1,49 @@
# 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.
@@ -0,0 +1,109 @@
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))
@@ -0,0 +1,54 @@
{
"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"
}
}
@@ -0,0 +1,3 @@
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`
@@ -0,0 +1,2 @@
Checking oa-core v0.2.0 (C:\ar-diagram-01a0d717\crates\oa-core)
Finished `dev` profile [unoptimized] target(s) in 17.18s
@@ -0,0 +1,14 @@
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
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
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`
@@ -0,0 +1,6 @@
{
"returncode": 3221225781,
"hex": "0xc0000135",
"stdout": "",
"stderr": ""
}
@@ -0,0 +1,41 @@
# 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.
@@ -0,0 +1,39 @@
# 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.
@@ -0,0 +1,278 @@
{
"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
}
}
@@ -0,0 +1,33 @@
{
"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"
}
}
}
@@ -0,0 +1,23 @@
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']
@@ -0,0 +1,23 @@
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']
Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

@@ -0,0 +1,58 @@
# Issue 38 assisted native diagram review
Continuation of ../review.md on the same app/fixture. Parent-supplied executable and fixture identities and the opening-view cue caveat in that report remain applicable. The earlier phase is not pristine blind accuracy evidence. This assisted phase intentionally uses visible Inspector and Connections data; no source, JSON, geometry, answer key or semantic oracle was read.
Normal launch window, complete representative mixed view, Traceability projection, Fit 52% throughout. Approximately 220.7 seconds from first assisted observation to final Escape, including observation, UI navigation, and progress messages; recording the report excluded. No pan/zoom, model edit, Apply changes, Save, filtering, hiding, projection change, placement, route edit, label edit, port attachment edit, or property edit occurred. Selection and Inspector scroll only. App left open, 0 selected, Fit52%; navigator expanded naturally while following ports.
## Relations selected by visible labels
All three requested label clicks succeeded immediately. Inspector titles and stable aliases established relation kind and identity. Scrolling the Inspector exposed port endpoint fields and UUIDs. UUIDs below are manual transcriptions of visible fields, with screenshots as evidence.
| Relation | Kind / alias / UUID | Semantic endpoints and visible owners |
| --- | --- | --- |
| Request field repair | Functional exchange; sa_repair_request; 93474111-f23e-56c1-b61b-b7c2396b91bd | Source Assess pressure alarm, @sa_assess, via Request field repair output @sa_repair_request_out; target Repair valve in the field via Request field repair input @sa_repair_request_in |
| Report repair result | Functional exchange; sa_repair_report; 684eadc3-e670-5779-a60f-bbc9a5bfb062 | Source Repair valve in the field via Report repair result output @sa_repair_report_out; target Confirm safe pressure @sa_confirm via Report repair result input @sa_repair_report_in |
| Technician service conversation | Boundary exchange; sa_contact; 63009b5f-539e-5914-b630-ec6b7febf4d5 | Source field Repair service client @sa_control_port, owned by Pressure coordination service; target field Repair service provider @sa_technician_port, owned by Field technician. Directed exchange checkbox unchecked, so participants are unordered semantically. |
All three show Valve repair @sa_repair_operation in Items. A shared item does not make these relations equivalent. The conversation uses boundary ports; the other exchanges use functional ports and function endpoints.
Request full-path highlighting resolves the otherwise difficult bend near Assess pressure alarm and approach to the upper Repair port. Report highlighting resolves the apparent branch toward Reset valve remotely: its selected path continues to Confirm safe pressure, while the reset branch remains gray.
Conversation selection materially clarifies label association: the selected green route travels from the system's right square marker left of the label to an upward segment, ending at the actor's left square marker. The label remains far to the right, next to a different actor-to-function allocation stroke. The label selects the intended conversation, but its visual placement suggests the wrong nearby route when unselected. See 05 and 06.
Owner evidence was inspected separately using port markers and visible Parent/semantic-parent fields and tooltips, not inferred solely from shared card locations. See 13, 18 through 22.
## Two distinct port mappings
| Mapping | Alias / UUID | Semantic port endpoints |
| --- | --- | --- |
| Port allocation: Report repair result output | sa_port_report_out; e53b7a40-e8a3-5b3f-826d-c2b5c164a84a | Repair service provider @sa_technician_port -> Report repair result output @sa_repair_report_out |
| Port allocation: Request field repair input | sa_port_request_in; 09eaa992-4cdf-5ea3-b748-f10fd74b8cba | Repair service provider @sa_technician_port -> Request field repair input @sa_repair_request_in |
Both are Port allocation relations. Their source port is owned by Field technician; their distinct target ports are owned by Repair valve in the field. They share displayed owner cards and an upper route corridor, but they have distinct port endpoints, aliases, UUIDs, and lower approach geometry. See 10 through 19.
### Actual attempts and wrong turns
1. First guessed actor-to-function stroke at (933,520), followed by another click at that point and (904,572), selected Allocation: Repair valve in the field, alias sa_repair_allocation, UUID 725f2e1b-aa2c-5615-9b1f-28da178168fa. Inspector showed Source Field technician @sa_technician and Target Repair valve in the field. This is the ordinary card allocation, not either port mapping. The wrong turn followed the visually obvious line near the misplaced conversation label. Repeated clicks did not cycle alternatives.
2. Connections on that allocation showed REFERENCES to Field technician and Repair valve in the field. Clicking Field technician opened its Connections page. The actor's OUTGOING RELATIONSHIPS showed the ordinary allocation only; its CONTAINS section exposed Repair service provider. Thus owner-level Connections did not directly expose these port-level mappings, but a discoverable contained-port traversal did.
3. Clicking Repair service provider showed OWNED BY Field technician, OUTGOING RELATIONSHIPS containing interface provision plus two separately named Port allocation entries, and incoming Technician service conversation. Relation row titles selected the actual relations; the distinct Open target actions instead navigate to a referenced endpoint. See 10.
4. Clicked Port allocation: Report repair result output title, then Properties. Its entire selected path followed the actor's left square, then left and down in the tall corridor to the lower Repair port. Captured exact identity and semantic source/target fields.
5. Clicked the now-known shared upper stroke at (806,502) twice. Report mapping selection remained; there was no visible picker or cycle. This alone does not prove a fixed preference because a mapping was already selected.
6. Clicked provider square marker (865,451), then Connections, then Port allocation: Request field repair input title, then Properties. Request mapping was separately reachable, with a different UUID and upper Repair input endpoint.
7. Clicking shared stroke (806,502) with request selected retained request. A blank canvas click did not clear selection in this test. Escape did clear selection. Clicking (806,502) from 0 selected selected the request mapping. Therefore the observed behavior is selection-dependent retention / no cycling, with request chosen from the cleared state in this run, not a proven universal report-first rule. The earlier progress phrase saying the shared stroke repeatedly selects report was provisional and is superseded by these observations.
8. Clicking the lower corridor segment (806,627), below the request-port branch, selected the report mapping directly. Hence both mappings were reachable on canvas after their routes had been learned through Connections, and both were independently reachable through semantic relation entries. The low zoom and adjacent vertical paths make discovery considerably harder than access once the locations are known.
9. Selected request input, report output, service client, request output, and report input port markers to verify visible parent ownership and aliases. Ended with Escape, 0 selected.
## Outcome and limitations
Assisted relation reading succeeds through label selection, full-path highlighting, and Inspector fields. The unselected conversation label association remains misleading. Highlighting separates the report route from apparent branches and lets a reader verify ports rather than infer semantics from cards.
Distinct coincident mappings are accessible through port Connections and carefully chosen segments. Repeated clicking on their shared corridor does not expose an explicit alternative list or cycle in this run. Reaching the two by semantic navigation required going through the actor's contained port; this is possible but adds several steps and requires understanding the card/port distinction. Full names and stable aliases are often clipped inside narrow dropdowns, while the Connections row body and port tooltip supply useful full names.
This phase does not claim route editing, label persistence, model serialization, or equivalence under edits; those belong to a separately declared edit/oracle phase. No model edits were attempted.
## Screenshots
01-02 request label selection and fields; 03-04 report selection and fields; 05-06 conversation selection, displaced highlight, endpoints and unchecked direction; 07-08 initial ordinary-allocation wrong turn; 09 actor Connections; 10 provider Connections with both mappings; 11-12 report mapping; 13 provider ownership; 14-15 request mapping; 16 cleared-state shared-stroke selection of request; 17 direct lower-stroke selection of report; 18-22 port owner/alias verification.
All PNGs are archived native Computer Use captures, with no synthetic rendering or image transformation.
@@ -0,0 +1,38 @@
from pathlib import Path
import copy,hashlib,json,math
root=Path(__file__).resolve().parent
manual=root/'manual'
a=json.loads((manual/'geometry-before.json').read_text(encoding='utf-8'))
b=json.loads((manual/'geometry-after.json').read_text(encoding='utf-8'))
diagram='00000000-0038-4000-8000-000000000001'
edge='63009b5f-539e-5914-b630-ec6b7fefb4d5'
original=a['project'];saved=b['project']
assert original['diagrams'][diagram]['routes']==[]
routes=saved['diagrams'][diagram]['routes']
assert len(routes)==1 and set(routes[0])=={'edge','waypoints','label'}
route=routes[0]
assert route['edge']==edge and route['waypoints']==[]
assert route['label']['fraction']==0.5
assert set(route['label'])=={'fraction','offset'} and set(route['label']['offset'])=={'x','y'}
assert all(math.isfinite(v) for v in route['label']['offset'].values())
restored=copy.deepcopy(saved)
restored['diagrams'][diagram]['routes']=[]
assert restored==original, 'Unexpected other stored changes'
assert a['projected_view']==b['projected_view'] and a['projected_semantic_inventory']==b['projected_semantic_inventory']
ea={e['id']:e for e in a['routed_edges']};eb={e['id']:e for e in b['routed_edges']}
assert ea.keys()==eb.keys()
changed_labels=[]
for k in ea:
for field in ['points','projected','semantic','effective_pins','pin_fractions','custom_suspended','route_warnings']:
assert ea[k][field]==eb[k][field], (k,field)
if ea[k]['label']!=eb[k]['label']:changed_labels.append({'edge':k,'before':ea[k]['label'],'after':eb[k]['label']})
old=ea[edge]['label'];new=eb[edge]['label']
assert old['fraction']==new['fraction']==0.5 and old['anchor']==new['anchor']
delta={key:new['center'][key]-old['center'][key] for key in ['x','y']}
screen={'x':-48.,'y':-30.}
inferred_zoom={key:screen[key]/delta[key] for key in ['x','y']}
assert all(0.515<=z<0.525 for z in inferred_zoom.values()), inferred_zoom
assert abs(inferred_zoom['x']-inferred_zoom['y'])<0.00001
result={'status':'PASS','scope':'Complete stored Project and all 12 computed paths are conserved except the declared label metadata. Rendered labels are separately compared below.','stored_allowed_delta':route,'computed_labels_changed':changed_labels,'all_computed_paths_identical':True,'gesture':{'start_screen':[924,547],'end_screen':[876,517],'world_delta':delta,'inferred_zoom':inferred_zoom,'rounded_fit_zoom_percent':52,'method':'The predeclared screen displacement and observed center displacement must imply one zoom in the rounding interval for the visible Fit52%; no exact independent zoom was captured.'},'geometry_pins':{p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in [manual/'geometry-before.json',manual/'geometry-after.json']}}
(manual/'geometry-comparison.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print(json.dumps({'status':result['status'],'changed_computed_labels':[x['edge'] for x in changed_labels],'all_paths_identical':True,'gesture':result['gesture']},indent=2))
@@ -0,0 +1,25 @@
from pathlib import Path
import hashlib,json
root=Path(__file__).resolve().parent
before=root/'working/eight-card.json'
after=root/'working/project.json'
a=json.loads(before.read_text(encoding='utf-8'))
b=json.loads(after.read_text(encoding='utf-8'))
differences=[]
def compare(left,right,path=''):
if type(left)!=type(right):
differences.append({'path':path,'before':left,'after':right});return
if isinstance(left,dict):
for key in sorted(left.keys()|right.keys()):
if key not in left or key not in right:
differences.append({'path':path+'/'+key,'before':left.get(key),'after':right.get(key),'kind':'key change'})
else: compare(left[key],right[key],path+'/'+key)
elif isinstance(left,list):
if len(left)!=len(right):
differences.append({'path':path,'kind':'length change','before':len(left),'after':len(right)})
for i,(x,y) in enumerate(zip(left,right)): compare(x,y,path+'/'+str(i))
elif left!=right: differences.append({'path':path,'before':left,'after':right})
compare(a,b)
result={'before':{'path':str(before),'sha256':hashlib.sha256(before.read_bytes()).hexdigest()},'after':{'path':str(after),'sha256':hashlib.sha256(after.read_bytes()).hexdigest()},'differences':differences}
(root/'manual/full-diff.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print(json.dumps(result,indent=2))
@@ -0,0 +1,18 @@
{
"source": "6e7c4ddaf0775198384a8c4882809ea8e14b2976",
"routing_core_source": "715036e132677dd2bc2fb37ed316d93dc9987aec",
"fixture_probe_source": "f754ad85d3674a709d10054e6fe23079f977c547",
"start": "2026-10-02T01:06:58.733162+00:00",
"binary_sha256": "d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"fixture": "C:\\ar-diagram-01a0d717\\.local\\native-reading\\working\\eight-card.json",
"cwd": "C:\\ar-diagram-01a0d717\\.local\\native-reading\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 5612,
"exit_code": 0,
"finished": "2026-10-02T01:30:11.251047+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"fixture_unchanged": true
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

@@ -0,0 +1,18 @@
{
"before": {
"path": "C:\\ar-diagram-01a0d717\\.local\\native-reading\\working\\eight-card.json",
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"after": {
"path": "C:\\ar-diagram-01a0d717\\.local\\native-reading\\working\\project.json",
"sha256": "39572f8ab176f7b8ac8933a308dcf7b127aa15e3d4f627ef604325a5275812f2"
},
"differences": [
{
"path": "/diagrams/00000000-0038-4000-8000-000000000001/routes",
"kind": "length change",
"before": 0,
"after": 1
}
]
}

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