Compare commits

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

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

@@ -0,0 +1,11 @@
# Baseline native SVG export
Parent identity: source 6e7c4ddaf0775198384a8c4882809ea8e14b2976; executable SHA256 d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e; runtime prefix f456; PID 10220. Native window returned ID 16778564, app executable in extracted ArcadiaStudio-0.2.0-preview.compact-help.20261001-x86_64-pc-windows-gnullvm package under C:/ar-compact-01a0d717/.local/package39/extracted/.
Opened C:/ar-label-cue-01a0d717/.local/native-cue-baseline/working/eight-card.json with native Open. Initial Ctrl+A/type on apparent filename focus left the field empty; no Open was committed. Explicit pointer focus and one literal backslash-path retry displayed the exact intended path, then pointer Open loaded it. This transient chooser input observation is not classified as an application defect.
Switched System, selected Issue 38 representative eight-card mixed view, observed OA → SA traceability, clicked Fit and Escape. Target at 52%, 1442×932, eight cards visible, zero selection. Clicked Export SVG; in app-native Export diagram modal focused path, Ctrl+A, typed C:/ar-label-cue-01a0d717/.local/native-cue-baseline/working/baseline.svg and clicked Export diagram. Footer reported Diagram exported as SVG. Screenshots 00-path.png and 01-export-success.png.
No model edit, Apply, Save, JSON export, diagram selection or drag. No model/SVG text or bytes inspected. Parent owns file/model/XML comparison and output existence/hash validation. Experimental B and fresh-reader reports unchanged; no comparative interpretation made here.
Alt+F4 closed normally without an observed prompt. Fresh enumeration no longer listed Arcadia. Parent owns process exit/log checks. GUI relinquished.
@@ -0,0 +1,17 @@
{
"source": "6e7c4ddaf0775198384a8c4882809ea8e14b2976",
"start": "2026-10-02T02:05:58.837634+00:00",
"binary_sha256": "d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 10220,
"exit_code": 0,
"finished": "2026-10-02T02:09:43.777146+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"fixture_unchanged": true,
"binary_unchanged": true,
"runtime_unchanged": true
}
@@ -0,0 +1,10 @@
{
"source": "6e7c4ddaf0775198384a8c4882809ea8e14b2976",
"start": "2026-10-02T02:05:58.837634+00:00",
"binary_sha256": "d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 10220
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

@@ -0,0 +1,12 @@
# Native label-cue scene preparation
Scope: scene preparation only, before a separate fresh reader's first native inspection. Parent owns build identification, launch, fixture byte checks, and process logs. No GUI input or launch until exact parent readiness. Source branch inspected: `codex/label-cue-experiment-01a0d717-20261001`; clean tracked working tree at planning time.
1. On parent readiness, enumerate native windows and identify only the parent-launched experimental executable. Observe before each UI action using the Computer Use skill.
2. Open `C:/ar-label-cue-01a0d717/.local/native-cue/working/eight-card.json` through the native chooser. Focus the filename field and use Ctrl+A, literal typing, and actual Open/Return commit; do not use accessibility set_value.
3. In Architecture, switch to System perspective and choose the saved `Issue 38 representative eight-card mixed view`, then the Traceability projection. Resolve controls from actual screenshots. Do not expose intermediate OA or simpler SA views to the fresh reader.
4. Set normal 1440×900 client size (approximately 1442×932 outer screenshot), use Fit, and Escape to zero selection. Leave the target fully visible with no menu, Help, dialog, or element inspector overlay obstructing it. Do not edit, Apply, Save, drag, or infer relationship answers.
5. Save only the final target screenshot plus preparation report under `.local/native-cue/prep`. Record exact observed window size, zoom, header, zero selection, and visible card count. Record setup facts without decoding or naming diagram relationships for the reader.
6. Stop all GUI input and relinquish to the parent/new reader. The fresh reader's first view must be this complete target scene. Parent should give them no earlier source/geometry/results or preparation intermediate screenshots. Parent verifies pristine bytes independently.
If the target cannot be reached or the expected scene does not appear, stop and report the actual setup mismatch without editing or supplying inferred answers. No compilation, Gitea action, production edit, fixture generation, or app launch by this preparer.
@@ -0,0 +1,20 @@
{
"source": "3e5e094bb17877674f4f3ea027a25fc0bdecdfe7",
"experiment": "B guarded label cue; not production acceptance",
"profile": "dev/unoptimized",
"target": "x86_64-pc-windows-gnullvm",
"files": {
"bin\\arcadia-studio.exe": {
"bytes": 119575040,
"sha256": "38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04"
},
"bin\\libunwind.dll": {
"bytes": 190976,
"sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4"
},
"working\\eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

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

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

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

After

Width:  |  Height:  |  Size: 148 KiB

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

After

Width:  |  Height:  |  Size: 7.2 KiB

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