Compare commits

..
Author SHA1 Message Date
Codex-ytr83r 7c2b06b63f test: import text editor actions in Allocation regression 2026-09-23 23:44:24 -07:00
122 changed files with 54 additions and 30027 deletions
File diff suppressed because it is too large Load Diff
@@ -1,131 +0,0 @@
//! Independent structural falsifiers for incoming boundary ordering.
use super::*;
fn pair(f: &mut Builder, name: &str, x: f32) -> (Id, Id, Id) {
let parent = f.function(name, None, x, 40.0);
let a = f.function(&format!("{name} A"), Some(parent), x + 60.0, 130.0);
let b = f.function(&format!("{name} B"), Some(parent), x + 60.0, 330.0);
(parent, a, b)
}
pub(super) fn fixtures() -> Vec<(&'static str, Builder)> {
let mut all = Vec::new();
let mut f = Builder::new("boundary_opposing_parents");
let (_, la, lb) = pair(&mut f, "Left", 40.0);
let (_, ra, rb) = pair(&mut f, "Right", 820.0);
for (name, a, b) in [
("Reverse upper", la, rb),
("Reverse lower", lb, ra),
("Return upper", ra, la),
("Return lower", rb, lb),
] {
f.exchange(name, a, b);
}
all.push(("boundary_opposing_parents", f));
let mut f = Builder::new("boundary_three_parent_chain");
let (_, la, lb) = pair(&mut f, "Left", 40.0);
let (middle, ma, mb) = pair(&mut f, "Middle", 820.0);
let (_, ra, rb) = pair(&mut f, "Right", 1600.0);
for (name, a, b) in [
("Left upper", la, mb),
("Left lower", lb, ma),
("Middle upper", mb, ra),
("Middle lower", ma, rb),
] {
f.exchange(name, a, b);
}
let mut translated = f.clone();
for element in [middle, ma, mb] {
let node = translated.node(element);
let position = &mut translated
.project
.diagrams
.get_mut(&translated.diagram)
.unwrap()
.nodes
.get_mut(&node)
.unwrap()
.position;
position.x += 300.0;
position.y += 500.0;
}
let mut permuted = f.clone();
let ids: Vec<_> = permuted.project.relations.keys().copied().collect();
for (i, id) in ids.iter().enumerate() {
reidentify(
&mut permuted.project,
*id,
Id::from_u128(1_000_000 + i as u128),
)
.unwrap();
}
for (i, id) in ids.iter().rev().enumerate() {
reidentify(
&mut permuted.project,
Id::from_u128(1_000_000 + i as u128),
*id,
)
.unwrap();
}
all.push(("boundary_three_parent_chain", f));
all.push(("boundary_three_parent_translated", translated));
all.push(("boundary_three_parent_edge_ids_reversed", permuted));
let mut f = Builder::new("boundary_two_local_sccs");
let (_, sa, sb) = pair(&mut f, "Source", 40.0);
let target = f.function("Target", None, 820.0, 40.0);
let x1 = f.function("X1", Some(target), 880.0, 130.0);
let x2 = f.function("X2", Some(target), 1200.0, 130.0);
let y1 = f.function("Y1", Some(target), 880.0, 330.0);
let y2 = f.function("Y2", Some(target), 1200.0, 330.0);
let z = f.function("Z", Some(target), 1520.0, 230.0);
for (name, a, b) in [
("X forward", x1, x2),
("X back", x2, x1),
("Y forward", y1, y2),
("Y back", y2, y1),
("X result", x2, z),
("Y result", y2, z),
("Upper boundary", sa, y1),
("Lower boundary", sb, x1),
] {
f.exchange(name, a, b);
}
all.push(("boundary_two_local_sccs", f));
let mut f = super::fixtures()
.into_iter()
.find(|(name, _)| *name == "two_containers_reversed_children")
.unwrap()
.1;
let relations: Vec<_> = f.project.relations.values().cloned().collect();
for relation in relations {
if let RelationBody::FunctionalExchange {
source_port,
target_port,
..
} = relation.body
{
for (port, side, offset) in [
(source_port, PortAnchorSide::Right, 0.3),
(target_port, PortAnchorSide::Left, 0.7),
] {
let owner = f.project.elements[&port].parent.unwrap();
let node = f.node(owner);
f.project = prepare_command(
&f.project,
&Command::SetPortAnchor {
diagram: f.diagram,
node,
anchor: PortAnchor { port, side, offset },
},
)
.unwrap()
.project;
}
}
}
all.push(("boundary_two_containers_anchored", f));
all
}
@@ -1,279 +0,0 @@
//! Bounded flat-placement experiment. Empty lead diagnostics are necessary only,
//! never a claim that routes, labels, or drawing quality are acceptable.
use oa_core::{Id, ModelError, Project, projection, routing};
use std::collections::BTreeMap;
const ROUNDS: usize = 4;
const WORK_LIMIT: usize = 10_000_000;
const MAX_SPAN: f32 = 100_000.0;
const MARGIN: f32 = 1.0;
fn fail(message: &str) -> ModelError {
ModelError(format!("Clearance probe: {message}"))
}
fn spend(work: &mut usize, amount: usize) -> Result<(), ModelError> {
*work = work.saturating_add(amount);
if *work > WORK_LIMIT {
return Err(fail("work limit exceeded"));
}
Ok(())
}
// A boundary constraint means start[to] >= start[from] + extent[from] + gap.
// Adjacent total-order constraints below separately preserve start ordering.
type Constraints = BTreeMap<(usize, usize), f32>;
fn solve(
baseline: &[f32],
extents: &[f32],
order: &[usize],
constraints: &Constraints,
work: &mut usize,
) -> Result<Vec<f32>, ModelError> {
let mut result = baseline.to_vec();
let mut previous = None;
for &to in order {
if let Some(from) = previous {
result[to] = result[to].max(result[from]);
}
for (&(from, target), &gap) in constraints {
spend(work, 1)?;
if target == to {
result[to] = result[to].max(result[from] + extents[from] + gap);
}
}
previous = Some(to);
}
let minimum = baseline.iter().copied().fold(f32::INFINITY, f32::min);
for (i, &value) in result.iter().enumerate() {
if !value.is_finite() || value + extents[i] - minimum > MAX_SPAN {
return Err(fail("coordinate/span bound exceeded"));
}
}
Ok(result)
}
/// Input is an already admitted placement candidate. Never modifies its routes,
/// authored anchors, sizes or semantics. Error drops the private clone.
pub fn repair(project: &Project, diagram: Id) -> Result<Project, ModelError> {
let original = project
.diagrams
.get(&diagram)
.ok_or_else(|| fail("missing diagram"))?;
if original.projection.scenario().is_some() {
return Err(fail("Scenario unsupported"));
}
let baseline = projection::project_diagram(project, original);
if baseline.nodes.len() > 256 || baseline.edges.len() > 1024 {
return Err(fail("graph bound exceeded"));
}
if baseline.nodes.len() != original.nodes.len()
|| baseline
.nodes
.iter()
.any(|n| n.collapsed || n.visual_parent.is_some())
{
return Err(fail("nested, folded or omitted placements unsupported"));
}
let mut nodes = baseline.nodes.clone();
nodes.sort_by_key(|n| n.id);
if nodes.iter().any(|n| {
!n.position.x.is_finite()
|| !n.position.y.is_finite()
|| !n.size.width.is_finite()
|| !n.size.height.is_finite()
|| n.size.width <= 0.0
|| n.size.height <= 0.0
}) {
return Err(fail("invalid initial geometry"));
}
let indices: BTreeMap<_, _> = nodes.iter().enumerate().map(|(i, n)| (n.id, i)).collect();
let coordinates = [
nodes.iter().map(|n| n.position.x).collect::<Vec<_>>(),
nodes.iter().map(|n| n.position.y).collect::<Vec<_>>(),
];
let extents = [
nodes.iter().map(|n| n.size.width).collect::<Vec<_>>(),
nodes.iter().map(|n| n.size.height).collect::<Vec<_>>(),
];
for axis in 0..2 {
let minimum = coordinates[axis]
.iter()
.copied()
.fold(f32::INFINITY, f32::min);
if coordinates[axis]
.iter()
.zip(&extents[axis])
.any(|(&start, &extent)| {
!(start + extent).is_finite() || start + extent - minimum > MAX_SPAN
})
{
return Err(fail("initial coordinate/span bound exceeded"));
}
}
let mut orders = [Vec::new(), Vec::new()];
let mut ranks = [vec![0; nodes.len()], vec![0; nodes.len()]];
for axis in 0..2 {
orders[axis] = (0..nodes.len()).collect();
orders[axis].sort_by(|&a, &b| {
coordinates[axis][a]
.total_cmp(&coordinates[axis][b])
.then(nodes[a].id.cmp(&nodes[b].id))
});
for (rank, &i) in orders[axis].iter().enumerate() {
ranks[axis][i] = rank;
}
}
let mut constraints = [Constraints::new(), Constraints::new()];
let mut work = 0;
// Preserve one existing disjoint axis per pair, X before Y. No initially
// overlapping pair is silently treated as successfully repaired.
for a in 0..nodes.len() {
for b in a + 1..nodes.len() {
spend(&mut work, 1)?;
let mut chosen = None;
for axis in 0..2 {
for (from, to) in [(a, b), (b, a)] {
let gap = coordinates[axis][to] - coordinates[axis][from] - extents[axis][from];
if gap >= 0.0 {
chosen = Some((axis, from, to, gap));
break;
}
}
if chosen.is_some() {
break;
}
}
let (axis, from, to, gap) =
chosen.ok_or_else(|| fail("initial node overlap unsupported"))?;
constraints[axis].insert((from, to), gap);
}
}
let mut result = project.clone();
for round in 0..=ROUNDS {
let current = &result.diagrams[&diagram];
let view = projection::project_diagram(&result, current);
if view.nodes.len() != nodes.len()
|| view.nodes.iter().any(|n| {
indices.get(&n.id).is_none_or(|&i| {
n.size != nodes[i].size || n.collapsed || n.visual_parent.is_some()
})
})
{
return Err(fail("reprojection changed node identity/size/topology"));
}
// Charge work units proportional to node count and at most sixteen
// endpoint pairs. This is not an exact operation count or a bound on
// all projection work; graph, round and span limits apply separately.
spend(
&mut work,
view.edges
.len()
.saturating_mul(nodes.len().saturating_add(1))
.saturating_mul(16),
)?;
let failures = routing::lead_incompatibilities(&result, current, &view);
if failures.is_empty() {
return Ok(result);
}
if round == ROUNDS {
return Err(fail("unresolved mandatory leads after four adjustments"));
}
let mut strengthened = false;
for failure in failures {
if failure.allowed_pair_count != 1
|| failure.source.len() != 1
|| failure.target.len() != 1
{
return Err(fail("ambiguous endpoint choices unsupported"));
}
for endpoint in failure.source.iter().chain(&failure.target) {
let owner = *indices
.get(&endpoint.owner)
.ok_or_else(|| fail("unknown endpoint owner"))?;
let dx = endpoint.stub.x - endpoint.tip.x;
let dy = endpoint.stub.y - endpoint.tip.y;
if endpoint.blockers.is_empty() {
continue;
}
let (axis, forward) = match (dx, dy) {
(x, 0.0) if x != 0.0 => (0, x > 0.0),
(0.0, y) if y != 0.0 => (1, y > 0.0),
_ => return Err(fail("noncardinal/degenerate blocked lead")),
};
for blocker in &endpoint.blockers {
spend(&mut work, 1)?;
let other = *indices
.get(&blocker.id)
.ok_or_else(|| fail("unknown blocker"))?;
let (from, to) = if forward {
(owner, other)
} else {
(other, owner)
};
if ranks[axis][from] >= ranks[axis][to] {
return Err(fail("lead constraint opposes frozen spatial order"));
}
let required = routing::PORT_STUB + routing::CLEARANCE + MARGIN;
let old = constraints[axis].entry((from, to)).or_insert(0.0);
if *old < required {
*old = required;
strengthened = true;
}
}
}
}
if !strengthened {
return Err(fail(
"unresolved lead without a stronger monotone constraint",
));
}
let x = solve(
&coordinates[0],
&extents[0],
&orders[0],
&constraints[0],
&mut work,
)?;
let y = solve(
&coordinates[1],
&extents[1],
&orders[1],
&constraints[1],
&mut work,
)?;
let target = result.diagrams.get_mut(&diagram).unwrap();
for (i, node) in nodes.iter().enumerate() {
let placed = target.nodes.get_mut(&node.id).unwrap();
placed.position.x = x[i];
placed.position.y = y[i];
}
}
unreachable!("bounded loop returns on final round")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn separation_propagates_to_neighbor_without_moving_predecessor() {
let constraints = BTreeMap::from([((0, 1), 31.0), ((1, 2), 10.0)]);
let actual = solve(
&[-20.0, 100.0, 210.0],
&[100.0; 3],
&[0, 1, 2],
&constraints,
&mut 0,
)
.unwrap();
assert_eq!(actual, vec![-20.0, 111.0, 221.0]);
}
#[test]
fn extent_bound_rejects_constraint_expansion() {
let constraints = BTreeMap::from([((0, 1), MAX_SPAN)]);
assert!(solve(&[0.0, 20.0], &[10.0; 2], &[0, 1], &constraints, &mut 0).is_err());
}
}
@@ -1,654 +0,0 @@
//! Isolated SCC-block placement experiment; no production-layout acceptance.
use super::{PlacementNode, PlacementPlan, import_placement};
use oa_core::{Id, ModelError, Position, Project, Size, projection, routing};
use std::collections::{BTreeMap, BTreeSet};
const LIMIT: usize = 20_000_000;
const PAD: f32 = 32.0;
const SPAN: f32 = 100_000.0;
#[path = "condensed/boundary.rs"]
mod boundary;
fn error(text: &str) -> ModelError {
ModelError(format!("SCC placement: {text}"))
}
fn charge(work: &mut usize, count: usize) -> Result<(), ModelError> {
*work = work.saturating_add(count);
if *work > LIMIT {
Err(error("work limit exceeded"))
} else {
Ok(())
}
}
fn components(arcs: &[BTreeSet<usize>], work: &mut usize) -> Result<Vec<Vec<usize>>, ModelError> {
let n = arcs.len();
let mut reach = vec![vec![false; n]; n];
for (start, reachable) in reach.iter_mut().enumerate() {
let mut todo = vec![start];
reachable[start] = true;
while let Some(at) = todo.pop() {
for &next in &arcs[at] {
charge(work, 1)?;
if !reachable[next] {
reachable[next] = true;
todo.push(next);
}
}
}
}
let mut used = vec![false; n];
let mut result = Vec::new();
for i in 0..n {
if used[i] {
continue;
}
let mut group = Vec::new();
for j in i..n {
charge(work, 1)?;
if !used[j] && reach[i][j] && reach[j][i] {
used[j] = true;
group.push(j);
}
}
result.push(group);
}
Ok(result)
}
fn perimeter_slots(n: usize, rows: usize, cols: usize) -> Vec<(usize, usize)> {
let mut slots = Vec::new();
if rows == 1 {
slots.extend((0..cols).map(|col| (col, 0)));
} else if cols == 1 {
slots.extend((0..rows).map(|row| (0, row)));
} else {
slots.extend((0..cols).map(|col| (col, 0)));
slots.extend((1..rows).map(|row| (cols - 1, row)));
slots.extend((0..cols - 1).rev().map(|col| (col, rows - 1)));
slots.extend((1..rows - 1).rev().map(|row| (0, row)));
}
slots.truncate(n);
slots
}
// Score occupied maximum-member cells, excluding unused perimeter slots.
// Heterogeneous members may occupy less than this nominal cell envelope.
fn perimeter(
n: usize,
cell: Size,
gap: Size,
work: &mut usize,
) -> Result<(Vec<Position>, usize, usize), ModelError> {
type GridScore = (bool, f32, f32, usize, usize);
let mut best: Option<(GridScore, usize, usize)> = None;
for rows in 1..=n {
for cols in 1..=n {
charge(work, 1)?;
let capacity = if rows == 1 || cols == 1 {
rows * cols
} else {
2 * rows + 2 * cols - 4
};
if capacity < n {
continue;
}
charge(work, capacity)?;
let slots = perimeter_slots(n, rows, cols);
let max_x = slots.iter().map(|p| p.0).max().unwrap();
let max_y = slots.iter().map(|p| p.1).max().unwrap();
let width = (max_x + 1) as f32 * cell.width + max_x as f32 * gap.width;
let height = (max_y + 1) as f32 * cell.height + max_y as f32 * gap.height;
let aspect = (width / height).max(height / width);
let key = (
aspect > 2.0,
if aspect <= 2.0 {
width * height
} else {
aspect
},
width * height,
rows,
cols,
);
if best.as_ref().is_none_or(|(old, _, _)| key < *old) {
best = Some((key, rows, cols));
}
}
}
let (_, rows, cols) = best.ok_or_else(|| error("no perimeter grid"))?;
let slots = perimeter_slots(n, rows, cols);
Ok((
slots
.into_iter()
.take(n)
.map(|(x, y)| Position {
x: x as f32 * (cell.width + gap.width),
y: y as f32 * (cell.height + gap.height),
})
.collect(),
rows,
cols,
))
}
fn lift(
id: Id,
parent: Option<Id>,
parents: &BTreeMap<Id, Option<Id>>,
work: &mut usize,
) -> Result<Option<Id>, ModelError> {
let mut at = id;
for _ in 0..=parents.len() {
charge(work, 1)?;
let Some(&up) = parents.get(&at) else {
return Err(error("missing visual ancestor"));
};
if up == parent {
return Ok(Some(at));
}
let Some(next) = up else {
return Ok(None);
};
at = next;
}
Err(error("cyclic visual ancestry"))
}
/// Frozen projected geometry is the minimum; folded nodes remain opaque.
pub fn candidate(project: &Project, diagram: Id) -> Result<Project, ModelError> {
candidate_with_diagnostics(project, diagram).map(|(result, _)| result)
}
pub fn candidate_with_diagnostics(
project: &Project,
diagram: Id,
) -> Result<(Project, serde_json::Value), ModelError> {
candidate_policy(project, diagram, false)
}
pub fn boundary_candidate_with_diagnostics(
project: &Project,
diagram: Id,
) -> Result<(Project, serde_json::Value), ModelError> {
candidate_policy(project, diagram, true)
}
fn candidate_policy(
project: &Project,
diagram: Id,
order_boundaries: bool,
) -> Result<(Project, serde_json::Value), ModelError> {
let d = project
.diagrams
.get(&diagram)
.ok_or_else(|| error("missing diagram"))?;
if d.projection.scenario().is_some() {
return Err(error("Scenario unsupported"));
}
if d.nodes.len() > 256 {
return Err(error("stored-node bound exceeded"));
}
let view = projection::project_diagram(project, d);
if view.edges.len() > 1024 {
return Err(error("visible-edge bound exceeded"));
}
if view.nodes.iter().any(|n| {
!n.size.width.is_finite()
|| !n.size.height.is_finite()
|| n.size.width <= 0.0
|| n.size.height <= 0.0
}) {
return Err(error("invalid projected minima"));
}
let parents: BTreeMap<_, _> = view.nodes.iter().map(|n| (n.id, n.visual_parent)).collect();
let names: BTreeMap<_, _> = view
.nodes
.iter()
.map(|n| (n.id, (project.elements[&n.element].alias.clone(), n.id)))
.collect();
let mut children: BTreeMap<Option<Id>, Vec<Id>> = BTreeMap::new();
for n in &view.nodes {
children.entry(n.visual_parent).or_default().push(n.id);
}
for ids in children.values_mut() {
ids.sort_by_key(|id| names[id].clone());
}
let mut work = 0;
let mut depth = BTreeMap::new();
for n in &view.nodes {
let mut at = n.id;
let mut count = 0;
let mut seen = BTreeSet::new();
while let Some(up) = *parents.get(&at).ok_or_else(|| error("missing parent"))? {
charge(&mut work, 1)?;
if !seen.insert(at) {
return Err(error("cyclic hierarchy"));
}
count += 1;
at = up;
}
depth.insert(n.id, count);
}
let routed = routing::route_diagram(project, d, &view);
let mut sizes: BTreeMap<_, _> = view.nodes.iter().map(|n| (n.id, n.size)).collect();
let mut offsets = BTreeMap::new();
let mut diagnostics = Vec::new();
let mut boundary_groups = Vec::new();
let mut groups: Vec<_> = children.keys().copied().collect();
groups.sort_by_key(|p| std::cmp::Reverse(p.map_or(0, |id| depth[&id] + 1)));
for parent in groups {
let ids = &children[&parent];
let index: BTreeMap<_, _> = ids.iter().enumerate().map(|(i, id)| (*id, i)).collect();
let mut arcs = vec![BTreeSet::new(); ids.len()];
let mut links = Vec::new();
let mut undirected = BTreeSet::new();
for edge in &view.edges {
charge(&mut work, 1)?;
let (Some(a), Some(b)) = (
lift(edge.source, parent, &parents, &mut work)?,
lift(edge.target, parent, &parents, &mut work)?,
) else {
continue;
};
if a == b {
continue;
}
let (a, b) = (index[&a], index[&b]);
if edge.oriented {
arcs[a].insert(b);
} else {
undirected.insert((ids[a].min(ids[b]), ids[a].max(ids[b])));
}
let routed_edge = routed
.edges
.get(&edge.id)
.ok_or_else(|| error("missing estimated edge label"))?;
let mut label = routed_edge.label.bounds.size;
if let Some(relation) = project.relations.get(&edge.id) {
for end in routing::association_end_geometry(relation, routed_edge) {
label.width = label.width.max(end.label.bounds.size.width);
label.height = label.height.max(end.label.bounds.size.height);
}
}
if !label.width.is_finite() || !label.height.is_finite() {
return Err(error("invalid estimated label"));
}
links.push((a, b, label));
}
let comps = components(&arcs, &mut work)?;
let mut owner = vec![0; ids.len()];
for (c, members) in comps.iter().enumerate() {
for &i in members {
owner[i] = c;
}
}
let mut dag = vec![BTreeSet::new(); comps.len()];
for (a, targets) in arcs.iter().enumerate() {
for &b in targets {
if owner[a] != owner[b] {
dag[owner[a]].insert(owner[b]);
}
}
}
let mut ranks = vec![0usize; comps.len()];
let mut done = BTreeSet::new();
while done.len() < comps.len() {
let next = (0..comps.len())
.find(|c| {
!done.contains(c)
&& (0..comps.len()).all(|p| !dag[p].contains(c) || done.contains(&p))
})
.ok_or_else(|| error("condensation is cyclic"))?;
charge(&mut work, comps.len() * comps.len())?;
for &to in &dag[next] {
ranks[to] = ranks[to].max(ranks[next] + 1);
}
done.insert(next);
}
let mut blocks = Vec::new();
let mut component_diagnostics = Vec::new();
let mut member_offsets = BTreeMap::new();
for (c, members) in comps.iter().enumerate() {
let mut gap = Size {
width: PAD,
height: PAD,
};
for &(a, b, label) in &links {
if owner[a] == c && owner[b] == c {
gap.width = gap.width.max(label.width + PAD);
gap.height = gap.height.max(label.height + PAD);
}
}
let mut order = Vec::new();
let mut seen = BTreeSet::new();
for &start in members {
let mut stack = vec![start];
while let Some(i) = stack.pop() {
charge(&mut work, 1)?;
if !seen.insert(i) {
continue;
}
order.push(i);
for &j in arcs[i].iter().rev() {
if owner[j] == c && !seen.contains(&j) {
stack.push(j);
}
}
}
}
let cell = Size {
width: members
.iter()
.map(|&i| sizes[&ids[i]].width)
.fold(0.0, f32::max),
height: members
.iter()
.map(|&i| sizes[&ids[i]].height)
.fold(0.0, f32::max),
};
let (slots, rows, cols) = if members.len() == 1 {
(vec![Position { x: 0.0, y: 0.0 }], 1, 1)
} else {
perimeter(members.len(), cell, gap, &mut work)?
};
component_diagnostics.push(serde_json::json!({"component":c,"rank":ranks[c],"members":members.iter().map(|&i|ids[i]).collect::<Vec<_>>(),"walk":order.iter().map(|&i|ids[i]).collect::<Vec<_>>(),"grid_rows":rows,"grid_cols":cols,"gap":gap}));
let mut size = Size {
width: 0.0,
height: 0.0,
};
for (i, pos) in order.into_iter().zip(slots) {
size.width = size.width.max(pos.x + sizes[&ids[i]].width);
size.height = size.height.max(pos.y + sizes[&ids[i]].height);
member_offsets.insert(i, pos);
}
blocks.push(size);
}
let max_rank = ranks.iter().copied().max().unwrap_or(0);
charge(
&mut work,
links
.len()
.saturating_mul(comps.len().saturating_add(1))
.saturating_mul(comps.len().saturating_add(1)),
)?;
let mut block_positions = vec![Position { x: 0.0, y: 0.0 }; comps.len()];
let mut x = 0.0;
let mut total = Size {
width: 0.0,
height: 0.0,
};
let mut prior_order = vec![0usize; comps.len()];
let mut bands = Vec::new();
for rank in 0..=max_rank {
let mut layer: Vec<_> = (0..comps.len()).filter(|&c| ranks[c] == rank).collect();
// Fixed one-pass proximity order, including undirected links, without
// inventing direction or changing condensation ranks.
layer.sort_by_key(|&c| {
let neighbors: Vec<_> = links
.iter()
.filter_map(|&(a, b, _)| {
let (a, b) = (owner[a], owner[b]);
if a == c && ranks[b] < rank {
Some(prior_order[b])
} else if b == c && ranks[a] < rank {
Some(prior_order[a])
} else {
None
}
})
.collect();
(
if neighbors.is_empty() {
c
} else {
neighbors.iter().sum::<usize>() / neighbors.len()
},
c,
)
});
// Keep same-rank undirected neighbours contiguous in one canonical
// breadth-first walk; these links never become directed rank arcs.
let mut proximity = Vec::new();
let mut remaining: BTreeSet<_> = layer.iter().copied().collect();
for &start in &layer {
if !remaining.remove(&start) {
continue;
}
let mut queue = std::collections::VecDeque::from([start]);
while let Some(c) = queue.pop_front() {
proximity.push(c);
for &next in &layer {
charge(&mut work, links.len() + 1)?;
if remaining.contains(&next)
&& links.iter().any(|&(a, b, _)| {
(owner[a] == c && owner[b] == next)
|| (owner[b] == c && owner[a] == next)
})
{
remaining.remove(&next);
queue.push_back(next);
}
}
}
}
layer = proximity;
let mut cut = Size {
width: PAD,
height: PAD,
};
for &(a, b, label) in &links {
if owner[a] != owner[b] && (ranks[owner[a]] == rank || ranks[owner[b]] == rank) {
cut.width = cut.width.max(label.width + PAD);
cut.height = cut.height.max(label.height + PAD);
}
}
let mut y = 0.0;
let mut width = 0.0_f32;
if order_boundaries && parent.is_some() {
bands.push(boundary::Band {
components: layer.clone(),
gap: cut.height,
});
}
for (i, c) in layer.into_iter().enumerate() {
prior_order[c] = i;
block_positions[c] = Position { x, y };
y += blocks[c].height + cut.height;
width = width.max(blocks[c].width);
}
total.width = total.width.max(x + width);
total.height = total.height.max((y - cut.height).max(0.0));
x += width + cut.width;
}
let header = if let Some(id) = parent {
let n = view.nodes.iter().find(|n| n.id == id).unwrap();
if n.collapsed {
return Err(error("folded node has projected children"));
}
if d.projection.state_machine().is_some() {
projection::state_header_height(project, n.element)
} else {
64.0
}
} else {
0.0
};
for (i, id) in ids.iter().enumerate() {
let b = block_positions[owner[i]];
let m = member_offsets[&i];
offsets.insert(
*id,
Position {
x: b.x + m.x + if parent.is_some() { PAD } else { 0.0 },
y: b.y + m.y + if parent.is_some() { header + PAD } else { 0.0 },
},
);
}
if let Some(id) = parent {
let size = sizes.get_mut(&id).unwrap();
size.width = size.width.max(total.width + 2.0 * PAD);
size.height = size.height.max(total.height + header + 2.0 * PAD);
if order_boundaries {
boundary_groups.push(boundary::Group {
parent: id,
blocks: comps
.iter()
.enumerate()
.map(|(c, members)| boundary::Block {
members: members.iter().map(|&i| ids[i]).collect(),
size: blocks[c],
position: block_positions[c],
})
.collect(),
bands,
undirected: undirected
.iter()
.map(|(a, b)| (owner[index[a]], owner[index[b]]))
.collect(),
});
}
}
let lifted: Vec<_> = arcs
.iter()
.enumerate()
.flat_map(|(a, targets)| targets.iter().map(move |&b| (ids[a], ids[b])))
.collect();
diagnostics.push(serde_json::json!({"visible_parent":parent,"components":component_diagnostics,"directed_lifted_edges":lifted,"undirected_lifted_pairs":undirected,"block_positions":block_positions,"bounds":total,"policy":"SCCs of sibling-subtree quotient, not global semantic SCCs. Undirected edges affect local gap and deterministic proximity only; no rank direction invented."}));
}
let boundary_report = if order_boundaries {
let report = boundary::reorder(
&mut boundary_groups,
&parents,
&mut offsets,
&sizes,
&view.edges,
&mut work,
)?;
for group in &boundary_groups {
let diagnostic = diagnostics
.iter_mut()
.find(|entry| entry["visible_parent"] == serde_json::json!(group.parent))
.unwrap();
diagnostic["block_positions"] =
serde_json::json!(group.blocks.iter().map(|b| b.position).collect::<Vec<_>>());
}
Some(report)
} else {
None
};
let mut plans = Vec::new();
for n in &view.nodes {
let mut position = offsets[&n.id];
let mut parent = n.visual_parent;
while let Some(id) = parent {
charge(&mut work, 1)?;
let p = offsets[&id];
position.x += p.x;
position.y += p.y;
parent = parents[&id];
}
position.x += 40.0;
position.y += 40.0;
let size = sizes[&n.id];
if !position.x.is_finite()
|| !position.y.is_finite()
|| position.x + size.width > SPAN
|| position.y + size.height > SPAN
{
return Err(error("extent bound exceeded"));
}
plans.push(PlacementNode {
id: n.id,
position,
size,
});
}
let result = import_placement(
project,
diagram,
PlacementPlan {
schema: 1,
nodes: plans,
},
)?;
let final_view = projection::project_view(&result, diagram);
charge(
&mut work,
final_view.edges.len() * (final_view.nodes.len() + 1) * 16,
)?;
if !routing::lead_incompatibilities(&result, &result.diagrams[&diagram], &final_view).is_empty()
{
return Err(error(
"final mandatory port lead incompatible; no repair attempted",
));
}
let mut report = serde_json::json!({"groups":diagnostics,"work_charged":work,"work_limit":LIMIT,"scope":"Projected-forest quotient heuristic; actual final reprojection and necessary lead guard checked. No full-route or readability acceptance."});
if let Some(boundary_report) = boundary_report {
report["boundary_order"] = boundary_report;
}
Ok((result, report))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn directed_cycles_remain_separate_across_one_way_bridge() {
let arcs = vec![
BTreeSet::from([1]),
BTreeSet::from([0, 2]),
BTreeSet::from([3]),
BTreeSet::from([2]),
];
assert_eq!(
components(&arcs, &mut 0).unwrap(),
vec![vec![0, 1], vec![2, 3]]
);
}
#[test]
fn perimeter_places_ten_unique_cells_without_overlap() {
let (positions, _, _) = perimeter(
10,
Size {
width: 224.0,
height: 132.0,
},
Size {
width: 32.0,
height: 32.0,
},
&mut 0,
)
.unwrap();
assert_eq!(positions.len(), 10);
for (i, a) in positions.iter().enumerate() {
for b in &positions[i + 1..] {
assert!((a.x - b.x).abs() >= 256.0 || (a.y - b.y).abs() >= 164.0);
}
}
}
#[test]
fn two_node_perimeter_scores_occupied_cells_instead_of_an_unused_row() {
let (positions, rows, cols) = perimeter(
2,
Size {
width: 224.0,
height: 160.0,
},
Size {
width: 250.0,
height: 56.0,
},
&mut 0,
)
.unwrap();
assert_eq!((rows, cols), (2, 1));
assert_eq!(
positions,
vec![Position { x: 0.0, y: 0.0 }, Position { x: 0.0, y: 216.0 }]
);
}
}
@@ -1,686 +0,0 @@
//! One deterministic boundary-order pass; dependency cycles use frozen scores.
use super::{charge, components, error, lift};
use oa_core::{Id, ModelError, Position, Size, projection::ProjectedEdge};
use std::collections::{BTreeMap, BTreeSet};
pub(super) struct Block {
pub members: Vec<Id>,
pub size: Size,
pub position: Position,
}
pub(super) struct Band {
pub components: Vec<usize>,
pub gap: f32,
}
pub(super) struct Group {
pub parent: Id,
pub blocks: Vec<Block>,
pub bands: Vec<Band>,
pub undirected: BTreeSet<(usize, usize)>,
}
#[derive(Clone)]
struct Unit {
blocks: Vec<usize>,
sources: BTreeSet<Id>,
hints: Vec<(Id, Id, Id)>,
}
fn center(
id: Id,
parents: &BTreeMap<Id, Option<Id>>,
offsets: &BTreeMap<Id, Position>,
sizes: &BTreeMap<Id, Size>,
work: &mut usize,
) -> Result<f64, ModelError> {
let mut at = Some(id);
let mut seen = BTreeSet::new();
let mut y = 0.0_f32;
while let Some(node) = at {
charge(work, 1)?;
if !seen.insert(node) {
return Err(error("boundary cyclic ancestry"));
}
let pos = offsets
.get(&node)
.ok_or_else(|| error("boundary missing offset"))?;
if !pos.x.is_finite() || !pos.y.is_finite() {
return Err(error("boundary nonfinite offset"));
}
if seen.len() == 1 {
y = pos.y;
} else {
y += pos.y;
}
if !y.is_finite() {
return Err(error("boundary composed position overflow"));
}
at = *parents
.get(&node)
.ok_or_else(|| error("boundary missing parent"))?;
}
let size = sizes
.get(&id)
.ok_or_else(|| error("boundary missing source size"))?;
y += 40.0;
let center = f64::from(y) + f64::from(size.height) / 2.0;
if !center.is_finite() {
return Err(error("boundary nonfinite center"));
}
Ok(center)
}
fn translate(value: f32, old_origin: f32, new_origin: f32) -> Result<f32, ModelError> {
// Bound the complete displacement, including origin subtraction. A rounded
// f32 delta can hide lost relative precision even when its addition is exact.
let intended = f64::from(value) + (f64::from(new_origin) - f64::from(old_origin));
let next = intended as f32;
if !next.is_finite() || (f64::from(next) - intended).abs() > 0.001 {
return Err(error("boundary member translation precision exceeded"));
}
Ok(next)
}
fn score(
unit: &Unit,
parents: &BTreeMap<Id, Option<Id>>,
offsets: &BTreeMap<Id, Position>,
sizes: &BTreeMap<Id, Size>,
work: &mut usize,
) -> Result<Option<f64>, ModelError> {
if unit.sources.is_empty() {
return Ok(None);
}
let mut total = 0.0;
for &source in &unit.sources {
total += center(source, parents, offsets, sizes, work)?;
}
let value = total / unit.sources.len() as f64;
if !value.is_finite() {
return Err(error("boundary nonfinite mean"));
}
Ok(Some(value))
}
fn ordered_units(scores: &[Option<f64>]) -> Vec<usize> {
let mut anchored: Vec<_> = (0..scores.len()).filter(|&i| scores[i].is_some()).collect();
anchored.sort_by(|&a, &b| {
scores[a]
.unwrap()
.total_cmp(&scores[b].unwrap())
.then(a.cmp(&b))
});
let mut next = anchored.into_iter();
(0..scores.len())
.map(|i| {
if scores[i].is_some() {
next.next().unwrap()
} else {
i
}
})
.collect()
}
fn packing(
blocks: &[Block],
before: &[usize],
after: &[usize],
gap: f32,
) -> Result<Vec<f32>, ModelError> {
const EPS: f64 = 0.001;
let origin = f64::from(blocks[before[0]].position.y);
let mut canonical = origin;
for &c in before {
if (f64::from(blocks[c].position.y) - canonical).abs() > EPS {
return Err(error("boundary non-prefix canonical band"));
}
canonical += f64::from(blocks[c].size.height) + f64::from(gap);
}
let mut next = origin;
let mut ys = Vec::new();
for &c in after {
let y = next as f32;
if !y.is_finite() || (f64::from(y) - next).abs() > EPS {
return Err(error("boundary prefix precision bound exceeded"));
}
ys.push(y);
next += f64::from(blocks[c].size.height) + f64::from(gap);
}
if (next - canonical).abs() > EPS {
return Err(error("boundary envelope changed"));
}
if before == after {
Ok(before.iter().map(|&c| blocks[c].position.y).collect())
} else {
Ok(ys)
}
}
pub(super) fn reorder(
groups: &mut [Group],
parents: &BTreeMap<Id, Option<Id>>,
offsets: &mut BTreeMap<Id, Position>,
sizes: &BTreeMap<Id, Size>,
edges: &[ProjectedEdge],
work: &mut usize,
) -> Result<serde_json::Value, ModelError> {
let mut group_order: Vec<_> = (0..groups.len()).collect();
group_order.sort_by_key(|&i| groups[i].parent);
let mut offset_owner = BTreeMap::new();
let mut parent_seen = BTreeSet::new();
let mut units: Vec<Vec<Vec<Unit>>> = vec![Vec::new(); groups.len()];
let mut active = BTreeSet::new();
for &g in &group_order {
let group = &groups[g];
if !parent_seen.insert(group.parent) || !parents.contains_key(&group.parent) {
return Err(error("boundary duplicate/missing group parent"));
}
let mut child_block = BTreeMap::new();
for (c, block) in group.blocks.iter().enumerate() {
if !block.size.width.is_finite()
|| !block.size.height.is_finite()
|| block.size.width <= 0.0
|| block.size.height <= 0.0
|| !block.position.x.is_finite()
|| !block.position.y.is_finite()
{
return Err(error("boundary invalid block geometry"));
}
for &id in &block.members {
if parents.get(&id) != Some(&Some(group.parent))
|| !offsets.contains_key(&id)
|| child_block.insert(id, c).is_some()
|| offset_owner.insert(id, g).is_some()
{
return Err(error("boundary invalid child membership"));
}
}
}
let mut covered = BTreeSet::new();
for band in &group.bands {
if !band.gap.is_finite() || band.gap < 0.0 || band.components.is_empty() {
return Err(error("boundary invalid band"));
}
let local: BTreeMap<_, _> = band
.components
.iter()
.enumerate()
.map(|(i, &c)| (c, i))
.collect();
for &c in &band.components {
if c >= group.blocks.len() || !covered.insert(c) {
return Err(error("boundary duplicate/unknown band block"));
}
}
let mut arcs = vec![BTreeSet::new(); band.components.len()];
for &(a, b) in &group.undirected {
charge(work, 1)?;
if let (Some(&a), Some(&b)) = (local.get(&a), local.get(&b)) {
arcs[a].insert(b);
arcs[b].insert(a);
}
}
let bundles = components(&arcs, work)?;
let mut band_units = Vec::new();
for bundle in bundles {
if bundle.windows(2).any(|v| v[1] != v[0] + 1) {
return Err(error("boundary undirected bundle not contiguous"));
}
let blocks: Vec<_> = bundle.iter().map(|&i| band.components[i]).collect();
let mut unit = Unit {
blocks,
sources: BTreeSet::new(),
hints: Vec::new(),
};
for edge in edges {
charge(work, 1)?;
if !edge.oriented {
continue;
}
let target = lift(edge.target, Some(group.parent), parents, work)?;
let Some(target) = target else {
continue;
};
if !unit.blocks.contains(
child_block
.get(&target)
.ok_or_else(|| error("boundary missing lifted target"))?,
) {
continue;
}
if lift(edge.source, Some(group.parent), parents, work)?.is_none() {
unit.sources.insert(edge.source);
unit.hints.push((edge.id, edge.source, edge.target));
}
}
unit.hints.sort();
band_units.push(unit);
}
if band_units.iter().filter(|u| !u.sources.is_empty()).count() >= 2 {
active.insert(g);
}
units[g].push(band_units);
}
if covered.len() != group.blocks.len() {
return Err(error("boundary incomplete band inventory"));
}
}
let active_order: Vec<_> = group_order
.into_iter()
.filter(|g| active.contains(g))
.collect();
let active_index: BTreeMap<_, _> = active_order
.iter()
.enumerate()
.map(|(i, &g)| (g, i))
.collect();
let mut dependencies = vec![BTreeSet::new(); active_order.len()];
let mut dependency_evidence = BTreeSet::new();
for (&g, &gi) in &active_index {
for unit in units[g].iter().flatten() {
for &source in &unit.sources {
let mut at = Some(source);
let mut seen = BTreeSet::new();
while let Some(node) = at {
charge(work, 1)?;
if !seen.insert(node) {
return Err(error("boundary dependency ancestry cycle"));
}
if let Some(&owner) = offset_owner.get(&node)
&& let Some(&oi) = active_index.get(&owner)
{
dependencies[oi].insert(gi);
dependency_evidence.insert((
groups[owner].parent,
groups[g].parent,
source,
node,
));
}
at = *parents
.get(&node)
.ok_or_else(|| error("boundary missing dependency ancestor"))?;
}
}
}
}
let sccs = components(&dependencies, work)?;
let mut scc_owner = vec![0; active_order.len()];
for (s, members) in sccs.iter().enumerate() {
for &i in members {
scc_owner[i] = s;
}
}
let mut dag = vec![BTreeSet::new(); sccs.len()];
for (a, targets) in dependencies.iter().enumerate() {
for &b in targets {
if scc_owner[a] != scc_owner[b] {
dag[scc_owner[a]].insert(scc_owner[b]);
}
}
}
let mut done = BTreeSet::new();
let mut records = Vec::new();
let mut processed = Vec::new();
while done.len() < sccs.len() {
charge(work, sccs.len() * sccs.len())?;
let s = (0..sccs.len())
.find(|s| {
!done.contains(s)
&& (0..sccs.len()).all(|p| !dag[p].contains(s) || done.contains(&p))
})
.ok_or_else(|| error("boundary condensation cycle"))?;
// Score the entire dependency SCC before modifying any offsets.
let mut snapshots = Vec::new();
for &i in &sccs[s] {
let g = active_order[i];
for (b, band_units) in units[g].iter().enumerate() {
let scores = band_units
.iter()
.map(|u| score(u, parents, offsets, sizes, work))
.collect::<Result<Vec<_>, _>>()?;
snapshots.push((g, b, scores));
}
}
for (g, b, scores) in snapshots {
let band_units = &units[g][b];
let order = ordered_units(&scores);
let before = groups[g].bands[b].components.clone();
let gap = groups[g].bands[b].gap;
let after: Vec<_> = order
.iter()
.flat_map(|&u| band_units[u].blocks.iter().copied())
.collect();
let ys = packing(&groups[g].blocks, &before, &after, gap)?;
let mut changed = Vec::new();
for (&c, y) in after.iter().zip(ys) {
charge(work, groups[g].blocks[c].members.len() + 1)?;
let old = groups[g].blocks[c].position.y;
if !y.is_finite() {
return Err(error("boundary packing overflow"));
}
if y != old {
changed.push(c);
}
for id in &groups[g].blocks[c].members {
let p = offsets
.get_mut(id)
.ok_or_else(|| error("boundary lost member offset"))?;
p.y = translate(p.y, old, y)?;
}
groups[g].blocks[c].position.y = y;
}
groups[g].bands[b].components = after.clone();
let changed_units: Vec<_> = band_units
.iter()
.enumerate()
.filter(|(_, u)| u.blocks.iter().any(|c| changed.contains(c)))
.map(|(i, _)| i)
.collect();
records.push(serde_json::json!({"parent":groups[g].parent,"band":b,"before_blocks":before,"after_blocks":after,"unit_order":order,"scores":scores,"changed_blocks":changed,"changed_units":changed_units,"envelope_epsilon":0.001,"units":band_units.iter().map(|u|serde_json::json!({"blocks":u.blocks,"source_owners":u.sources,"edge_hints":u.hints})).collect::<Vec<_>>()}));
}
processed.push(serde_json::json!({"parents":sccs[s].iter().map(|&i|groups[active_order[i]].parent).collect::<Vec<_>>(),"cyclic":sccs[s].len()>1||sccs[s].iter().any(|&i|dependencies[i].contains(&i)),"policy":"all scores snapshotted before one simultaneous group-permutation pass"}));
done.insert(s);
}
Ok(
serde_json::json!({"active_parents":active_order.iter().map(|&g|groups[g].parent).collect::<Vec<_>>(),"dependencies":dependency_evidence,"dependency_components":processed,"bands":records,"limitation":"One pass; cyclic dependencies use a common snapshot, not a fixed-point solution. Root unchanged; no quality or repeat-stability acceptance."}),
)
}
#[cfg(test)]
mod tests {
use super::*;
fn id(n: u128) -> Id {
Id::from_u128(n)
}
fn block(n: u128, y: f32, height: f32) -> Block {
Block {
members: vec![id(n)],
size: Size {
width: 10.0,
height,
},
position: Position { x: 0.0, y },
}
}
fn edge(n: u128, source: u128, target: u128) -> ProjectedEdge {
ProjectedEdge {
id: id(n),
source: id(source),
target: id(target),
trace: false,
oriented: true,
source_port: None,
target_port: None,
}
}
#[test]
fn anchored_sort_preserves_unanchored_ordinal_slot() {
assert_eq!(
ordered_units(&[Some(90.0), None, Some(10.0), Some(10.0)]),
vec![2, 1, 3, 0]
);
}
#[test]
fn heterogeneous_blocks_use_new_prefix_not_old_slots() {
let blocks = vec![
Block {
members: vec![],
size: Size {
width: 10.0,
height: 100.0,
},
position: Position { x: 0.0, y: 0.0 },
},
Block {
members: vec![],
size: Size {
width: 10.0,
height: 20.0,
},
position: Position { x: 0.0, y: 132.0 },
},
];
assert_eq!(
packing(&blocks, &[0, 1], &[1, 0], 32.0).unwrap(),
vec![0.0, 52.0]
);
}
#[test]
fn center_includes_grandparent_offset_change() {
let (a, b, c) = (Id::from_u128(1), Id::from_u128(2), Id::from_u128(3));
let parents = BTreeMap::from([(a, None), (b, Some(a)), (c, Some(b))]);
let mut offsets = BTreeMap::from([
(a, Position { x: 0.0, y: 100.0 }),
(b, Position { x: 0.0, y: 20.0 }),
(c, Position { x: 0.0, y: 5.0 }),
]);
let sizes = BTreeMap::from([(
c,
Size {
width: 10.0,
height: 10.0,
},
)]);
assert_eq!(
center(c, &parents, &offsets, &sizes, &mut 0).unwrap(),
170.0
);
offsets.get_mut(&a).unwrap().y += 300.0;
assert_eq!(
center(c, &parents, &offsets, &sizes, &mut 0).unwrap(),
470.0
);
}
#[test]
fn ancestor_dependency_updates_downstream_scores_before_its_permutation() {
// Downstream parent1 sorts before upstream20, so an absent ancestor
// dependency would leave downstream order unchanged and fail this test.
let mut groups = vec![
Group {
parent: id(1),
blocks: vec![block(2, 0.0, 100.0), block(3, 132.0, 100.0)],
bands: vec![Band {
components: vec![0, 1],
gap: 32.0,
}],
undirected: BTreeSet::new(),
},
Group {
parent: id(20),
blocks: vec![block(21, 0.0, 100.0), block(22, 132.0, 100.0)],
bands: vec![Band {
components: vec![0, 1],
gap: 32.0,
}],
undirected: BTreeSet::new(),
},
];
let parents = BTreeMap::from([
(id(1), None),
(id(2), Some(id(1))),
(id(3), Some(id(1))),
(id(20), None),
(id(21), Some(id(20))),
(id(22), Some(id(20))),
(id(23), Some(id(21))),
(id(30), None),
(id(31), None),
(id(32), None),
]);
let mut offsets: BTreeMap<_, _> = [
(1, 0.0),
(2, 0.0),
(3, 132.0),
(20, 0.0),
(21, 0.0),
(22, 132.0),
(23, 10.0),
(30, 300.0),
(31, 0.0),
(32, 50.0),
]
.into_iter()
.map(|(n, y)| (id(n), Position { x: 0.0, y }))
.collect();
let sizes = parents
.keys()
.map(|&n| {
(
n,
Size {
width: 10.0,
height: 10.0,
},
)
})
.collect();
let edges = vec![
edge(101, 30, 21),
edge(102, 31, 22),
edge(103, 23, 2),
edge(104, 32, 3),
];
let report = reorder(&mut groups, &parents, &mut offsets, &sizes, &edges, &mut 0).unwrap();
assert_eq!(groups[1].bands[0].components, vec![1, 0]);
assert_eq!(groups[0].bands[0].components, vec![1, 0]);
assert_eq!(offsets[&id(21)].y, 132.0);
assert_eq!(offsets[&id(23)].y, 10.0); // descendant is not directly moved
assert_eq!(
center(id(23), &parents, &offsets, &sizes, &mut 0).unwrap(),
187.0
);
assert_eq!(
report["dependency_components"][0]["parents"][0],
serde_json::json!(id(20))
);
}
#[test]
fn undirected_bundle_stays_whole_around_unanchored_unit() {
let mut groups = vec![Group {
parent: id(100),
blocks: vec![
block(101, 0.0, 20.0),
block(102, 30.0, 30.0),
block(103, 70.0, 40.0),
block(104, 120.0, 10.0),
],
bands: vec![Band {
components: vec![0, 1, 2, 3],
gap: 10.0,
}],
undirected: BTreeSet::from([(0, 1)]),
}];
let parents = BTreeMap::from([
(id(100), None),
(id(101), Some(id(100))),
(id(102), Some(id(100))),
(id(103), Some(id(100))),
(id(104), Some(id(100))),
(id(110), None),
(id(111), None),
]);
let mut offsets: BTreeMap<_, _> = [
(100, 0.0),
(101, 0.0),
(102, 30.0),
(103, 70.0),
(104, 120.0),
(110, 300.0),
(111, 0.0),
]
.into_iter()
.map(|(n, y)| (id(n), Position { x: 0.0, y }))
.collect();
let sizes = parents
.keys()
.map(|&n| {
(
n,
Size {
width: 10.0,
height: 10.0,
},
)
})
.collect();
let report = reorder(
&mut groups,
&parents,
&mut offsets,
&sizes,
&[
edge(201, 110, 101),
edge(202, 110, 102),
edge(203, 111, 104),
],
&mut 0,
)
.unwrap();
assert_eq!(groups[0].bands[0].components, vec![3, 2, 0, 1]);
assert_eq!(
[
offsets[&id(104)].y,
offsets[&id(103)].y,
offsets[&id(101)].y,
offsets[&id(102)].y
],
[0.0, 20.0, 70.0, 100.0]
);
assert_eq!(
report["bands"][0]["units"][0]["source_owners"]
.as_array()
.unwrap()
.len(),
1
);
}
#[test]
fn center_uses_final_plan_f32_composition_and_translation_has_error_bound() {
let parents = BTreeMap::from([(id(1), None), (id(2), Some(id(1))), (id(3), Some(id(2)))]);
let offsets = BTreeMap::from([
(
id(1),
Position {
x: 0.0,
y: -100000.0,
},
),
(
id(2),
Position {
x: 0.0,
y: 100000.0,
},
),
(id(3), Position { x: 0.0, y: 0.1 }),
]);
let sizes = BTreeMap::from([(
id(3),
Size {
width: 10.0,
height: 10.0,
},
)]);
assert_eq!(
center(id(3), &parents, &offsets, &sizes, &mut 0).unwrap(),
45.1015625
);
assert_eq!(translate(10.125, 0.0, 0.375).unwrap(), 10.5);
assert!(translate(32768.0, 0.0, 0.002).is_err());
}
#[test]
fn member_offset_survives_large_origin_subtraction() {
let blocks = vec![
block(1, 0.0, 65404.0),
block(2, 65436.0, 68.0),
block(3, 65536.0, 100.0),
block(4, 65668.0, 68.002),
];
let ys = packing(&blocks, &[0, 1, 2, 3], &[3, 2, 1, 0], 32.0).unwrap();
let member = translate(65568.0, 65536.0, ys[1]).unwrap();
assert!((f64::from(member) - f64::from(ys[1]) - 32.0).abs() <= 0.001);
}
}
@@ -1,380 +0,0 @@
//! Isolated #32 experiment, not a production layout engine.
//! Uses existing Layout sizing, three deterministic ordering passes, and one
//! core-estimated-label spacing pass. Automatic elbows remain derived. Folded/omitted
//! node topology is explicitly unsupported; filtered edges retain their metadata.
use oa_core::{Command, Id, ModelError, Position, Project, Size, projection, routing};
use std::collections::{BTreeMap, BTreeSet};
const WORK_LIMIT: usize = 200_000;
const NODE_LIMIT: usize = 256;
const EDGE_LIMIT: usize = 1024;
fn spend(work: &mut usize) -> Result<(), ModelError> {
*work += 1;
if *work > WORK_LIMIT {
return Err(ModelError("Layered probe work limit exceeded.".into()));
}
Ok(())
}
/// Return a new Project; caller owns comparison, history and serialization.
pub fn candidate(project: &Project, diagram: Id) -> Result<Project, ModelError> {
let original = project
.diagrams
.get(&diagram)
.ok_or_else(|| ModelError("Missing probe diagram.".into()))?;
let view = projection::project_diagram(project, original);
if view.nodes.len() > NODE_LIMIT || view.edges.len() > EDGE_LIMIT {
return Err(ModelError("Layered probe graph limit exceeded.".into()));
}
if view.nodes.len() != original.nodes.len() || view.nodes.iter().any(|n| n.collapsed) {
return Err(ModelError(
"Layered probe does not support folded/omitted node topology.".into(),
));
}
let routed = routing::route_diagram(project, original, &view);
let eligible: BTreeSet<_> = view
.edges
.iter()
.filter(|edge| {
projection::edge_endpoint_placements(project, original, edge.id)
== Some((edge.source, edge.target))
&& routed
.edges
.get(&edge.id)
.is_some_and(|route| !route.custom_suspended)
})
.map(|edge| edge.id)
.collect();
let mut result = oa_core::prepare_command(project, &Command::Layout(diagram))?.project;
// Discard baseline route translation: final routes are reconstructed directly
// from original geometry, avoiding two translations and preserving list order.
result.diagrams.get_mut(&diagram).unwrap().routes = original.routes.clone();
for route in &mut result.diagrams.get_mut(&diagram).unwrap().routes {
if eligible.contains(&route.edge) {
route.waypoints.clear();
route.label = None;
}
}
let baseline = projection::project_view(&result, diagram);
let labels = routing::route_diagram(&result, &result.diagrams[&diagram], &baseline);
let mut gap_x = 64.0_f32;
let mut gap_y = 32.0_f32;
for edge in labels.edges.values() {
gap_x = gap_x.max(edge.label.bounds.size.width + 24.0);
gap_y = gap_y.max(edge.label.bounds.size.height + 24.0);
if let Some(relation) = result.relations.get(&edge.id) {
for end in routing::association_end_geometry(relation, edge) {
gap_x = gap_x.max(end.label.bounds.size.width + 24.0);
gap_y = gap_y.max(end.label.bounds.size.height + 24.0);
}
}
}
if !gap_x.is_finite() || !gap_y.is_finite() {
return Err(ModelError("Nonfinite estimated label bound.".into()));
}
let parents: BTreeMap<_, _> = baseline
.nodes
.iter()
.map(|n| (n.id, n.visual_parent))
.collect();
let mut children: BTreeMap<Option<Id>, Vec<Id>> = BTreeMap::new();
for node in &baseline.nodes {
children
.entry(node.visual_parent)
.or_default()
.push(node.id);
}
let names: BTreeMap<_, _> = baseline
.nodes
.iter()
.map(|n| (n.id, (result.elements[&n.element].alias.clone(), n.id)))
.collect();
for siblings in children.values_mut() {
siblings.sort_by_key(|id| names[id].clone());
}
let minima: BTreeMap<_, _> = baseline.nodes.iter().map(|n| (n.id, n.size)).collect();
let headers: BTreeMap<_, _> = baseline
.nodes
.iter()
.map(|n| {
(
n.id,
if original.projection.state_machine().is_some() {
projection::state_header_height(&result, n.element)
} else {
64.0
},
)
})
.collect();
let mut positions: BTreeMap<_, _> = baseline.nodes.iter().map(|n| (n.id, n.position)).collect();
let mut sizes = minima.clone();
let mut work = 0;
let mut group_order: Vec<_> = children.keys().copied().collect();
group_order.sort_by_key(|parent| {
parent.map_or(0, |id| {
baseline.nodes.iter().find(|n| n.id == id).unwrap().depth + 1
})
});
let mut groups = BTreeMap::new();
for pass in 0..3 {
for parent in &group_order {
let siblings = &children[parent];
let mut arcs = BTreeSet::new();
for edge in &baseline.edges {
spend(&mut work)?;
let a = child_under(edge.source, *parent, &parents, &mut work)?;
let b = child_under(edge.target, *parent, &parents, &mut work)?;
if edge.oriented
&& let (Some(a), Some(b)) = (a, b)
&& a != b
{
arcs.insert((a, b));
}
}
let ranks = ranks(siblings, &arcs, &mut work)?;
let mut layers: BTreeMap<usize, Vec<Id>> = BTreeMap::new();
for id in siblings {
layers.entry(ranks[id]).or_default().push(*id);
}
// Boundary neighbours participate even though they are not siblings.
// Incoming preference anchors the downstream order to its upstream
// counterpart instead of swapping both sides simultaneously.
let mut scores = BTreeMap::new();
for id in siblings {
let mut incoming = Vec::new();
for edge in &baseline.edges {
spend(&mut work)?;
let a = child_under(edge.source, *parent, &parents, &mut work)?;
let b = child_under(edge.target, *parent, &parents, &mut work)?;
if edge.oriented && b == Some(*id) && a != Some(*id) {
incoming.push(positions[&edge.source].y + sizes[&edge.source].height / 2.0);
}
}
// Do not also chase outgoing boundary neighbours: simultaneous
// swaps in two connected containers can preserve the crossing.
let values = &incoming;
let score = if values.is_empty() {
positions[id].y
} else {
values.iter().sum::<f32>() / values.len() as f32
};
scores.insert(*id, score);
}
for layer in layers.values_mut() {
// First pass starts from canonical alias order; subsequent passes
// retain a deterministic alias tie break, never hash iteration.
if pass > 0 {
layer.sort_by(|a, b| {
scores[a]
.total_cmp(&scores[b])
.then_with(|| names[a].cmp(&names[b]))
});
}
}
groups.insert(*parent, layers.into_values().collect::<Vec<_>>());
}
// Recompute from frozen minima, never add spacing to last pass's size.
sizes = minima.clone();
measure(None, &groups, &headers, &mut sizes, gap_x, gap_y, &mut work)?;
place(
None,
Position { x: 40.0, y: 40.0 },
&groups,
&headers,
&sizes,
&mut positions,
gap_x,
gap_y,
&mut work,
)?;
}
let d = result.diagrams.get_mut(&diagram).unwrap();
for (id, node) in &mut d.nodes {
node.position = positions[id];
node.size = sizes[id];
}
let deltas: BTreeMap<_, _> = original
.nodes
.iter()
.map(|(id, node)| {
(
*id,
Position {
x: positions[id].x - node.position.x,
y: positions[id].y - node.position.y,
},
)
})
.collect();
let translated: BTreeMap<_, _> = projection::translated_routes(project, original, &deltas)
.into_iter()
.map(|r| (r.edge, r))
.collect();
d.routes = original
.routes
.iter()
.map(|route| {
let mut route = translated.get(&route.edge).unwrap_or(route).clone();
if eligible.contains(&route.edge) {
route.waypoints.clear();
route.label = None;
}
route
})
.collect();
if d.nodes.values().any(|n| {
!n.position.x.is_finite()
|| !n.position.y.is_finite()
|| !n.size.width.is_finite()
|| !n.size.height.is_finite()
|| n.size.width <= 0.0
|| n.size.height <= 0.0
}) {
return Err(ModelError("Invalid layered probe geometry.".into()));
}
oa_core::validate_candidate(&result)?;
Ok(result)
}
fn child_under(
mut id: Id,
parent: Option<Id>,
parents: &BTreeMap<Id, Option<Id>>,
work: &mut usize,
) -> Result<Option<Id>, ModelError> {
for _ in 0..=parents.len() {
spend(work)?;
let Some(actual) = parents.get(&id) else {
return Ok(None);
};
if *actual == parent {
return Ok(Some(id));
}
let Some(next) = actual else { return Ok(None) };
id = *next;
}
Err(ModelError("Layered probe containment cycle.".into()))
}
fn ranks(
ids: &[Id],
arcs: &BTreeSet<(Id, Id)>,
work: &mut usize,
) -> Result<BTreeMap<Id, usize>, ModelError> {
let mut remaining: BTreeSet<_> = ids.iter().copied().collect();
let mut ranks: BTreeMap<_, usize> = BTreeMap::new();
while !remaining.is_empty() {
let mut ready = None;
for id in ids.iter().filter(|id| remaining.contains(*id)) {
let mut blocked = false;
for (a, b) in arcs {
spend(work)?;
blocked |= b == id && remaining.contains(a);
}
if !blocked {
ready = Some(*id);
break;
}
}
// Explicit cycle fallback: break the first canonical remaining vertex's
// incoming ranking constraints. Actual relation direction is unchanged.
let id = ready.unwrap_or_else(|| *ids.iter().find(|id| remaining.contains(*id)).unwrap());
let mut rank = 0;
for (a, b) in arcs {
spend(work)?;
if *b == id
&& let Some(previous) = ranks.get(a)
{
rank = rank.max(previous + 1);
}
}
ranks.insert(id, rank);
remaining.remove(&id);
}
Ok(ranks)
}
type Groups = BTreeMap<Option<Id>, Vec<Vec<Id>>>;
fn measure(
parent: Option<Id>,
groups: &Groups,
headers: &BTreeMap<Id, f32>,
sizes: &mut BTreeMap<Id, Size>,
gx: f32,
gy: f32,
work: &mut usize,
) -> Result<Size, ModelError> {
let Some(layers) = groups.get(&parent) else {
return Ok(Size {
width: 0.0,
height: 0.0,
});
};
let mut width = 0.0;
let mut height = 0.0_f32;
for (i, layer) in layers.iter().enumerate() {
let mut lw = 0.0_f32;
let mut lh = 0.0;
for (j, id) in layer.iter().enumerate() {
spend(work)?;
let content = measure(Some(*id), groups, headers, sizes, gx, gy, work)?;
let size = sizes.get_mut(id).unwrap();
if groups.contains_key(&Some(*id)) {
size.width = size.width.max(content.width + 48.0);
size.height = size.height.max(content.height + headers[id] + 24.0);
}
lw = lw.max(size.width);
lh += size.height + if j == 0 { 0.0 } else { gy };
}
width += lw + if i == 0 { 0.0 } else { gx };
height = height.max(lh);
}
Ok(Size { width, height })
}
#[allow(clippy::too_many_arguments)]
fn place(
parent: Option<Id>,
origin: Position,
groups: &Groups,
headers: &BTreeMap<Id, f32>,
sizes: &BTreeMap<Id, Size>,
positions: &mut BTreeMap<Id, Position>,
gx: f32,
gy: f32,
work: &mut usize,
) -> Result<(), ModelError> {
let Some(layers) = groups.get(&parent) else {
return Ok(());
};
let mut x = origin.x;
for layer in layers {
let mut y = origin.y;
let mut width = 0.0_f32;
for id in layer {
spend(work)?;
positions.insert(*id, Position { x, y });
place(
Some(*id),
Position {
x: x + 24.0,
y: y + headers[id],
},
groups,
headers,
sizes,
positions,
gx,
gy,
work,
)?;
y += sizes[id].height + gy;
width = width.max(sizes[id].width);
}
x += width + gx;
}
Ok(())
}
@@ -1,192 +0,0 @@
//! Frozen-corpus route-only timing. Protocol: harness/experiments/routing-independent-20260925/timing-protocol.md.
use oa_core::{Id, Project, projection, routing, validate_candidate};
use serde::Deserialize;
use serde_json::json;
use std::hint::black_box;
use std::path::{Component, Path, PathBuf};
use std::time::{Duration, Instant};
const ROUNDS: usize = 7;
const SLOW_CALL: Duration = Duration::from_secs(5);
#[derive(Deserialize)]
struct Manifest {
schema: u32,
cases: Vec<Case>,
#[serde(flatten)]
metadata: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Deserialize)]
struct Case {
name: String,
project_file: PathBuf,
diagram: Id,
description: String,
#[serde(flatten)]
metadata: std::collections::BTreeMap<String, serde_json::Value>,
}
fn timed_route(
project: &Project,
diagram: &oa_core::Diagram,
view: &projection::ProjectedView,
) -> (routing::RoutedView, Duration) {
// Input black_box is outside the clock. Result consumption is inside it;
// allocation is part of routing, result destruction is outside the clock.
let project = black_box(project);
let diagram = black_box(diagram);
let view = black_box(view);
let started = Instant::now();
let result = black_box(routing::route_diagram(project, diagram, view));
let elapsed = started.elapsed();
(result, elapsed)
}
fn point_digest(route: &routing::RoutedView) -> String {
// Stable FNV-1a64 over ID bytes, point count and IEEE754 coordinate bits,
// little endian. Diagnostic only, not a cryptographic integrity guarantee.
let mut hash = 0xcbf29ce484222325_u64;
let mut feed = |bytes: &[u8]| {
for byte in bytes {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x100000001b3);
}
};
for (id, edge) in &route.edges {
feed(id.as_bytes());
feed(&(edge.points.len() as u64).to_le_bytes());
for point in &edge.points {
feed(&point.x.to_bits().to_le_bytes());
feed(&point.y.to_bits().to_le_bytes());
}
}
format!("{hash:016x}")
}
fn relative_project(root: &Path, file: &Path) -> Result<PathBuf, Box<dyn std::error::Error>> {
if file.as_os_str().is_empty()
|| !file
.components()
.all(|part| matches!(part, Component::Normal(_)))
{
return Err(
"project_file must be a nonempty relative path without parent traversal".into(),
);
}
let path = root.join(file).canonicalize()?;
if !path.starts_with(root) {
return Err("project_file resolves outside the manifest directory".into());
}
Ok(path)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut args = std::env::args_os().skip(1);
let manifest_path = PathBuf::from(
args.next()
.ok_or("usage: routing_cost_probe MANIFEST.json")?,
)
.canonicalize()?;
if args.next().is_some() {
return Err(
"protocol is fixed: one warmup and seven measured calls; no extra arguments".into(),
);
}
let manifest: Manifest = serde_json::from_slice(&std::fs::read(&manifest_path)?)?;
if manifest.schema != 1 || manifest.cases.is_empty() {
return Err("expected schema1 with at least one case".into());
}
let root = manifest_path
.parent()
.ok_or("manifest has no parent directory")?;
println!(
"{}",
json!({
"protocol": "routing_cost_probe_v1", "manifest_schema": manifest.schema,
"warmup_calls": 1, "measured_calls": ROUNDS,
"slow_call_limit_ns": SLOW_CALL.as_nanos(),
"debug_assertions": cfg!(debug_assertions),
"os": std::env::consts::OS, "arch": std::env::consts::ARCH,
"case_count": manifest.cases.len(),
"corpus_metadata": manifest.metadata,
"clock_scope": "route_diagram plus result black_box; excludes projection, JSON, equality, digest, output and result destruction",
"digest": "FNV-1a64 IDs/counts/f32 point bits; diagnostic, not cryptographic",
"acceptance": "none; external receipts must bind source, optimized build, binary and corpus"
})
);
let mut names = std::collections::BTreeSet::new();
for case in manifest.cases {
if !names.insert(case.name.clone()) {
return Err("duplicate case name".into());
}
let bytes = std::fs::read(relative_project(root, &case.project_file)?)?;
let project: Project = serde_json::from_slice(&bytes)?;
validate_candidate(&project)?;
let original = project.clone();
let diagram = project
.diagrams
.get(&case.diagram)
.ok_or("case diagram is absent")?;
let view = projection::project_diagram(&project, diagram);
let (first, warmup) = timed_route(&project, diagram, &view);
let mut samples = Vec::with_capacity(ROUNDS);
let mut equality = Vec::with_capacity(ROUNDS);
let mut endpoints = Vec::with_capacity(ROUNDS);
let mut censored = warmup > SLOW_CALL;
if !censored {
for _ in 0..ROUNDS {
let (route, elapsed) = timed_route(&project, diagram, &view);
samples.push(elapsed.as_nanos());
equality.push(route == first);
endpoints.push(
route.edges.len() == first.edges.len()
&& route.edges.iter().all(|(id, edge)| {
first.edges.get(id).is_some_and(|other| {
edge.points.first() == other.points.first()
&& edge.points.last() == other.points.last()
})
}),
);
if elapsed > SLOW_CALL {
censored = true;
break;
}
}
}
let mut ordered = samples.clone();
ordered.sort_unstable();
let complete = !censored && samples.len() == ROUNDS;
let median = complete.then(|| ordered[ROUNDS / 2]);
let warnings: usize = first.edges.values().map(|edge| edge.warnings.len()).sum();
let project_unchanged = project == original;
let stable = equality.iter().all(|same| *same);
println!(
"{}",
json!({
"case": case.name, "description": case.description,
"corpus_case_metadata": case.metadata,
"project_file": case.project_file, "diagram": case.diagram,
"project_bytes": bytes.len(), "nodes": view.nodes.len(),
"edges": view.edges.len(), "ports": view.ports.len(),
"routed_edges": first.edges.len(), "warnings": warnings,
"route_points": first.edges.values().map(|edge| edge.points.len()).sum::<usize>(),
"route_point_digest": point_digest(&first),
"warmup_ns": warmup.as_nanos(), "samples_ns": samples,
"median_ns": median, "max_observed_measured_ns": ordered.last(),
"complete": complete, "censored": censored,
"censor_reason": if censored { Some("single call exceeded five seconds; remaining repeats skipped") } else { None },
"repeat_full_routed_view_equal_warmup": equality,
"repeat_endpoints_equal_warmup": endpoints,
"stability_observed": !samples.is_empty(),
"project_unchanged": project_unchanged
})
);
if !stable || !project_unchanged {
return Err(
"routing stability or Project preservation failed; receipt above retained".into(),
);
}
}
Ok(())
}
@@ -1,555 +0,0 @@
//! Source-first inputs for independent routing experiments. Never invokes layout/routing.
use oa_core::*;
use serde_json::{Value, json};
use std::{collections::BTreeMap, error::Error, fs, path::PathBuf};
struct Case {
name: &'static str,
description: &'static str,
project: Project,
diagram: Id,
trace_edges: Vec<Id>,
metadata: Value,
}
struct Builder {
project: Project,
diagram: Id,
base: u128,
next: u128,
edges: Vec<Id>,
}
impl Builder {
fn new(name: &str, base: u128) -> Self {
let mut project = Project::empty();
project.id = Id::from_u128(base);
project.alias = name.into();
project.name = name.into();
let old = project.ensure_diagram(Layer::Sa);
let diagram = Id::from_u128(base + 1);
reidentify(&mut project, old, diagram).unwrap();
let d = project.diagrams.get_mut(&diagram).unwrap();
d.alias = format!("{name}_main");
d.name = format!("{name} main view");
d.projection = ProjectionKind::FunctionalDataflow;
Self {
project,
diagram,
base,
next: base + 100,
edges: Vec::new(),
}
}
fn stable(&mut self, old: Id) -> Id {
let id = Id::from_u128(self.next);
self.next += 1;
reidentify(&mut self.project, old, id).unwrap();
id
}
fn function(&mut self, name: &str, x: f32, y: f32) -> Id {
let old = self
.project
.add_element(Kind::Function, Layer::Sa, name, None)
.unwrap();
let id = self.stable(old);
let old = self.project.place(self.diagram, id, Position { x, y });
self.stable(old);
id
}
fn exchange(
&mut self,
name: &str,
source: Id,
target: Id,
source_port: PortChoice,
target_port: PortChoice,
) -> Id {
let id = Id::from_u128(self.base + 10_000 + self.edges.len() as u128);
let request = FunctionalExchangeRequest {
id,
alias: format!("flow_{:02}", self.edges.len()),
name: name.into(),
description: String::new(),
source,
target,
source_port,
target_port,
items: vec![],
};
let commands = ports::plan_functional_exchange(&self.project, &request).unwrap();
self.project = execute_batch(&self.project, &commands).unwrap();
self.edges.push(id);
id
}
fn port_pair(&self, edge: Id) -> (Id, Id) {
let RelationBody::FunctionalExchange {
source_port,
target_port,
..
} = self.project.relations[&edge].body
else {
unreachable!()
};
(source_port, target_port)
}
fn anchor(&mut self, owner: Id, port: Id, side: PortAnchorSide, offset: f32) {
let node = self.project.diagrams[&self.diagram]
.nodes
.values()
.find(|n| n.element == owner)
.unwrap()
.id;
self.project = prepare_command(
&self.project,
&Command::SetPortAnchor {
diagram: self.diagram,
node,
anchor: PortAnchor { port, side, offset },
},
)
.unwrap()
.project;
}
}
fn sentinel(edge: Id, x: f32, y: f32) -> EdgeRoute {
EdgeRoute {
edge,
source_attachment: None,
target_attachment: None,
waypoints: vec![Position { x, y }],
label: Some(EdgeLabel {
fraction: 0.4,
offset: Position { x: -30., y: -70. },
}),
}
}
fn workshop() -> Vec<Case> {
let original =
persistence::decode(include_bytes!("../../../examples/routing-workshop.json")).unwrap();
let diagram = original
.diagrams
.values()
.find(|d| d.alias == "sa_system_boundary_and_functions")
.unwrap()
.id;
assert_eq!(
original.diagrams[&diagram].projection,
ProjectionKind::Allocation
);
assert_eq!(original.diagrams[&diagram].nodes.len(), 12);
let container = original
.elements
.values()
.find(|e| e.alias == "rescue_coordination_system")
.unwrap()
.id;
let placement = original.diagrams[&diagram]
.nodes
.values()
.find(|n| n.element == container)
.unwrap()
.id;
let traces: Vec<_> = [
"sa_report_to_relay",
"sa_direct_advice",
"sa_incident_decision",
]
.iter()
.map(|alias| {
original
.relations
.values()
.find(|r| r.alias == *alias)
.unwrap()
.id
})
.collect();
let mut folded = original.clone();
assert!(!folded.diagrams[&diagram].nodes[&placement].collapsed);
folded
.diagrams
.get_mut(&diagram)
.unwrap()
.nodes
.get_mut(&placement)
.unwrap()
.collapsed = true;
let mut restored = folded.clone();
restored
.diagrams
.get_mut(&diagram)
.unwrap()
.nodes
.get_mut(&placement)
.unwrap()
.collapsed = false;
assert_eq!(restored, original);
vec![
Case {
name: "workshop_sa_original",
description: "Saved coastal rescue Allocation view, all source records retained.",
project: original,
diagram,
trace_edges: traces.clone(),
metadata: json!({"source":"examples/routing-workshop.json","view_alias":"sa_system_boundary_and_functions"}),
},
Case {
name: "workshop_sa_folded",
description: "Same saved Project with only rescue_coordination_system placement folded.",
project: folded,
diagram,
trace_edges: traces,
metadata: json!({"source":"examples/routing-workshop.json","folded_placement":placement,
"folded_element":container,"unfold_restores_original_exact":true}),
},
]
}
fn mixed() -> Vec<Case> {
let mut b = Builder::new("mixed_dispatch", 100_000);
let nodes: Vec<_> = [
("Sensor A", 40., 90.),
("Sensor B", 40., 510.),
("Ingest", 380., 250.),
("Validate", 720., 80.),
("Archive", 720., 510.),
("Correlate", 1060., 270.),
("Plan", 1400., 80.),
("Dispatch", 1740., 270.),
("Actuator", 1400., 680.),
("Operator", 1740., 680.),
]
.into_iter()
.map(|(name, x, y)| b.function(name, x, y))
.collect();
let e0 = b.exchange(
"Sensor A observations",
nodes[0],
nodes[2],
PortChoice::Create,
PortChoice::Create,
);
let ingest_input = b.port_pair(e0).1;
let e1 = b.exchange(
"Sensor B observations",
nodes[1],
nodes[2],
PortChoice::Create,
PortChoice::Reuse(ingest_input),
);
let e2 = b.exchange(
"Validate incoming observations",
nodes[2],
nodes[3],
PortChoice::Create,
PortChoice::Create,
);
let ingest_output = b.port_pair(e2).0;
let e3 = b.exchange(
"Archive incoming observations",
nodes[2],
nodes[4],
PortChoice::Reuse(ingest_output),
PortChoice::Create,
);
b.exchange(
"Validated observations",
nodes[3],
nodes[5],
PortChoice::Create,
PortChoice::Create,
);
b.exchange(
"Archived context",
nodes[4],
nodes[5],
PortChoice::Create,
PortChoice::Create,
);
b.exchange(
"Correlated situation",
nodes[5],
nodes[6],
PortChoice::Create,
PortChoice::Create,
);
b.exchange(
"Planned actions",
nodes[6],
nodes[7],
PortChoice::Create,
PortChoice::Create,
);
let e8 = b.exchange(
"Actuator dispatch",
nodes[7],
nodes[8],
PortChoice::Create,
PortChoice::Create,
);
let dispatch_output = b.port_pair(e8).0;
let e9 = b.exchange(
"Operator dispatch copy",
nodes[7],
nodes[9],
PortChoice::Reuse(dispatch_output),
PortChoice::Create,
);
b.exchange(
"Operator acknowledgement",
nodes[9],
nodes[8],
PortChoice::Create,
PortChoice::Create,
);
b.exchange(
"Archived actuator policy",
nodes[4],
nodes[8],
PortChoice::Create,
PortChoice::Create,
);
b.exchange(
"Sensor B archive stream",
nodes[1],
nodes[4],
PortChoice::Create,
PortChoice::Create,
);
let feedback = b.exchange(
"Sensor A sampling feedback",
nodes[6],
nodes[0],
PortChoice::Create,
PortChoice::Create,
);
let (feedback_output, feedback_input) = b.port_pair(feedback);
b.anchor(nodes[0], b.port_pair(e0).0, PortAnchorSide::Right, 0.25);
b.anchor(nodes[2], ingest_input, PortAnchorSide::Left, 0.3);
b.anchor(nodes[2], ingest_output, PortAnchorSide::Bottom, 0.6);
b.anchor(nodes[6], feedback_output, PortAnchorSide::Top, 0.5);
b.anchor(nodes[0], feedback_input, PortAnchorSide::Left, 0.6);
b.anchor(nodes[7], dispatch_output, PortAnchorSide::Right, 0.5);
b.project
.diagrams
.get_mut(&b.diagram)
.unwrap()
.routes
.push(sentinel(feedback, 300., -100.));
let secondary = Id::from_u128(b.base + 2);
let mut other = b.project.diagrams[&b.diagram].clone();
other.id = secondary;
other.alias = "mixed_dispatch_secondary".into();
other.name = "Feedback review sentinel".into();
other.description = "Unaffected other-view preservation sentinel".into();
other.nodes.clear();
other.routes = vec![sentinel(feedback, 460., 480.)];
b.project.diagrams.insert(secondary, other);
for (i, element) in [nodes[0], nodes[2], nodes[6]].into_iter().enumerate() {
let old = b.project.place(
secondary,
element,
Position {
x: 100. + i as f32 * 340.,
y: 100.,
},
);
let stable = b.stable(old);
b.project
.diagrams
.get_mut(&secondary)
.unwrap()
.nodes
.get_mut(&stable)
.unwrap()
.alias = format!("feedback_review_{i}");
}
assert_eq!(b.edges.len(), 14);
assert_eq!(b.project.diagrams[&b.diagram].nodes.len(), 10);
let originals = b.edges.clone();
let replacements: Vec<_> = originals.iter().rev().copied().collect();
let mut permuted = b.project.clone();
for (i, id) in originals.iter().enumerate() {
reidentify(&mut permuted, *id, Id::from_u128(1_000_000 + i as u128)).unwrap();
}
for (i, id) in replacements.iter().enumerate() {
reidentify(&mut permuted, Id::from_u128(1_000_000 + i as u128), *id).unwrap();
}
let mut restored = permuted.clone();
for (i, id) in replacements.iter().enumerate() {
reidentify(&mut restored, *id, Id::from_u128(1_000_000 + i as u128)).unwrap();
}
for (i, id) in originals.iter().enumerate() {
reidentify(&mut restored, Id::from_u128(1_000_000 + i as u128), *id).unwrap();
}
assert_eq!(restored, b.project);
let correspondence: BTreeMap<_, _> = originals.iter().copied().zip(replacements).collect();
let traces = vec![e1, e3, e9, feedback];
let permuted_traces = traces.iter().map(|id| correspondence[id]).collect();
let metadata = json!({"shared_input":ingest_input,"shared_outputs":[ingest_output,dispatch_output],
"sentinel_edge":feedback,"secondary_diagram":secondary,"fixed_anchor_records":6,
"authored_waypoint_count_main":1,"authored_label_count_main":1,
"declared_feedback_cycle":[nodes[0],nodes[2],nodes[3],nodes[5],nodes[6],nodes[0]]});
vec![
Case {
name: "mixed_dispatch",
description: "Ten-function sensing/decision/dispatch network, explicit port sharing and fixed anchors.",
project: b.project,
diagram: b.diagram,
trace_edges: traces,
metadata,
},
Case {
name: "mixed_dispatch_edge_ids_reversed",
description: "Same mixed Project with fixed reversed relation-ID permutation, remapped references.",
project: permuted,
diagram: b.diagram,
trace_edges: permuted_traces,
metadata: json!({"paired_case":"mixed_dispatch","edge_id_correspondence":correspondence,
"inverse_recovers_original_exact":true,"secondary_diagram":secondary}),
},
]
}
fn sparse() -> Case {
let mut b = Builder::new("subsystems_40_sparse", 200_000);
let names = [
"Sensing",
"Communications",
"Assessment",
"Planning",
"Delivery",
];
let stages = [
"Acquire",
"Decode",
"Validate",
"Enrich",
"Aggregate",
"Decide",
"Package",
"Publish",
];
let mut nodes = Vec::new();
for (group, name) in names.iter().enumerate() {
let row: Vec<_> = stages
.iter()
.enumerate()
.map(|(stage, label)| {
b.function(
&format!("{name} {label}"),
80. + stage as f32 * 300.,
80. + group as f32 * 240.,
)
})
.collect();
nodes.push(row);
}
for group in 0..5 {
for stage in 0..7 {
b.exchange(
&format!(
"{} {} to {}",
names[group],
stages[stage],
stages[stage + 1]
),
nodes[group][stage],
nodes[group][stage + 1],
PortChoice::Create,
PortChoice::Create,
);
}
}
let mut trace_edges = Vec::new();
for group in 0..5 {
for stage in [1, 3, 5, 7] {
let next = (group + 1) % 5;
let id = b.exchange(
&format!(
"{} {} handoff to {} {}",
names[group],
stages[stage],
names[next],
stages[stage - 1]
),
nodes[group][stage],
nodes[next][stage - 1],
PortChoice::Create,
PortChoice::Create,
);
if (group == 0 && stage == 1) || (group == 4 && stage == 7) {
trace_edges.push(id);
}
}
}
assert_eq!(b.edges.len(), 55);
assert_eq!(b.project.diagrams[&b.diagram].nodes.len(), 40);
Case {
name: "subsystems_40_sparse",
description: "Five eight-stage subsystem chains with twenty directed cross-subsystem handoffs; all ports distinct.",
project: b.project,
diagram: b.diagram,
trace_edges,
metadata: json!({"groups":names,"stages":stages,"chain_edges":35,"cross_edges":20,
"all_exchange_ports_distinct":true,"grid_columns":8,"grid_rows":5}),
}
}
fn main() -> Result<(), Box<dyn Error>> {
let mut args = std::env::args_os().skip(1);
let output = PathBuf::from(
args.next()
.ok_or("Usage: routing_eval_corpus NEW_DIRECTORY")?,
);
if args.next().is_some() {
return Err("Expected exactly one new output directory".into());
}
if output.exists() {
return Err("Output directory already exists; refusing overwrite".into());
}
let mut cases = workshop();
cases.extend(mixed());
cases.push(sparse());
let mut files = Vec::new();
let mut entries = Vec::new();
for case in cases {
validate_candidate(&case.project)?;
let file = format!("{}.json", case.name);
let traces: Vec<_> = case
.trace_edges
.iter()
.map(|id| {
let relation = &case.project.relations[id];
json!({"edge":id,"alias":relation.alias,"name":relation.name,
"source":relation.source(),"target":relation.target()})
})
.collect();
entries.push(json!({"name":case.name,"project_file":file,"diagram":case.diagram,
"description":case.description,"metadata":case.metadata,"trace_tasks":traces,
"source_counts":{"elements":case.project.elements.len(),"relations":case.project.relations.len(),
"views":case.project.diagrams.len(),"selected_view_placements":case.project.diagrams[&case.diagram].nodes.len(),
"selected_view_authored_routes":case.project.diagrams[&case.diagram].routes.len()}}));
files.push((file, serde_json::to_vec_pretty(&case.project)?));
}
let manifest = json!({"schema":1,"cases":entries,"definition_baseline":"f72aa2ca",
"construction":"Source-authored positions/topology, no Layout/projection/routing calls; validate all before writing.",
"invariants":"Routing is read-only. Preserve all semantic records, port identities, fixed anchors, authored routes/labels, fold flags, and other views. ID permutation correspondence is explicit. No quality or automatic endpoint-side expectation.",
"generation_in_routing_timing":false});
let manifest_bytes = serde_json::to_vec_pretty(&manifest)?;
fs::create_dir(&output)?;
for (name, bytes) in files {
fs::write(output.join(name), bytes)?;
}
fs::write(output.join("manifest.json"), manifest_bytes)?;
println!("{}", output.join("manifest.json").display());
Ok(())
}
+40 -76
View File
@@ -6,9 +6,7 @@ use crate::{
RelationBody, RelationKind, Size,
};
mod attachments;
mod leads;
pub use attachments::{attachment_from_point, attachment_point, semantic_port_endpoint};
pub use leads::{LeadBlocker, LeadEndpoint, LeadIncompatibility, lead_incompatibilities};
use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet, BinaryHeap};
use std::fmt;
@@ -422,73 +420,6 @@ fn endpoints(
.collect()
}
fn effective_route<'a>(
project: &Project,
diagram: &Diagram,
edge: &ProjectedEdge,
stored: Option<&'a crate::EdgeRoute>,
) -> (
bool,
Option<&'a crate::EdgeRoute>,
[Option<EdgeAttachment>; 2],
) {
let promoted = projection::edge_endpoint_placements(project, diagram, edge.id)
.is_some_and(|(source, target)| source != edge.source || target != edge.target);
let route = if promoted { None } else { stored };
let attachments = [EdgeEnd::Source, EdgeEnd::Target].map(|end| {
semantic_port_endpoint(project, edge.id, end)
.is_none()
.then(|| route.and_then(|r| r.attachment(end)))
.flatten()
});
(promoted, route, attachments)
}
#[allow(clippy::too_many_arguments)]
fn edge_endpoints(
project: &Project,
diagram: &Diagram,
edge: &ProjectedEdge,
source: &ProjectedNode,
target: &ProjectedNode,
view: &ProjectedView,
attachments: [Option<EdgeAttachment>; 2],
) -> [Vec<Endpoint>; 2] {
[
endpoints(
project,
diagram,
source,
semantic_port_endpoint(project, edge.id, EdgeEnd::Source).or(edge.source_port),
view,
attachments[0],
),
endpoints(
project,
diagram,
target,
semantic_port_endpoint(project, edge.id, EdgeEnd::Target).or(edge.target_port),
view,
attachments[1],
),
]
}
fn allowed_endpoint_pair(edge: &ProjectedEdge, a: Endpoint, b: Endpoint, coincident: bool) -> bool {
!(edge.source == edge.target
&& edge.source_port.is_none()
&& edge.target_port.is_none()
&& a.point == b.point
&& a.stub == b.stub
&& !coincident)
}
fn lead_pair_clear(edge: &ProjectedEdge, a: Endpoint, b: Endpoint, obstacles: &[Rect]) -> bool {
!obstacles
.iter()
.any(|r| r.id != edge.source && r.crosses(a.point, a.stub))
&& !obstacles
.iter()
.any(|r| r.id != edge.target && r.crosses(b.point, b.stub))
}
fn ancestors(id: Id, nodes: &BTreeMap<Id, &ProjectedNode>, out: &mut BTreeSet<Id>) {
let mut current = nodes.get(&id).and_then(|n| n.visual_parent);
let mut seen = BTreeSet::new();
@@ -581,8 +512,16 @@ fn route_diagram_impl(
continue;
};
let stored = authored.get(&edge.id).copied();
let (custom_suspended, route, attachments) =
effective_route(project, diagram, edge, stored);
let promoted = projection::edge_endpoint_placements(project, diagram, edge.id)
.is_some_and(|(source, target)| source != edge.source || target != edge.target);
let custom_suspended = promoted;
let route = if promoted { None } else { stored };
let attachments = [EdgeEnd::Source, EdgeEnd::Target].map(|end| {
semantic_port_endpoint(project, edge.id, end)
.is_none()
.then(|| route.and_then(|r| r.attachment(end)))
.flatten()
});
let pins = route.map_or_else(Vec::new, |r| r.waypoints.clone());
let obstacles = edge_obstacles(edge, &nodes, &rectangles, &headers);
@@ -620,11 +559,24 @@ fn route_diagram_impl(
});
}
}
let ends = edge_endpoints(project, diagram, edge, source, target, view, attachments);
let (points, pin_lengths, failure) = route_edge(
edge,
&ends[0],
&ends[1],
&endpoints(
project,
diagram,
source,
semantic_port_endpoint(project, edge.id, EdgeEnd::Source).or(edge.source_port),
view,
attachments[0],
),
&endpoints(
project,
diagram,
target,
semantic_port_endpoint(project, edge.id, EdgeEnd::Target).or(edge.target_port),
view,
attachments[1],
),
&pins,
&obstacles,
&previous,
@@ -841,7 +793,13 @@ fn route_edge(
for &b in target_ends {
// A real self-relation must leave and return at distinct anchors.
// Reusing one anchor makes the cheapest path a degenerate stub.
if !allowed_endpoint_pair(edge, a, b, coincident) {
if edge.source == edge.target
&& edge.source_port.is_none()
&& edge.target_port.is_none()
&& a.point == b.point
&& a.stub == b.stub
&& !coincident
{
continue;
}
let estimate = manhattan(a.stub, pins.first().copied().unwrap_or(b.stub))
@@ -865,7 +823,13 @@ fn route_edge(
}) {
continue;
}
if !lead_pair_clear(edge, a, b, obstacles) {
if obstacles
.iter()
.any(|r| r.id != edge.source && r.crosses(a.point, a.stub))
|| obstacles
.iter()
.any(|r| r.id != edge.target && r.crosses(b.point, b.stub))
{
continue;
}
let mut points = vec![a.point, a.stub];
-173
View File
@@ -1,173 +0,0 @@
//! Necessary terminal-lead checks shared with experimental placement consumers.
use super::*;
#[derive(Debug, Clone, PartialEq)]
pub struct LeadBlocker {
pub id: Id,
/// The actual routing obstacle: clearance inflated, ancestor body excluded.
pub bounds: RoutingBounds,
}
#[derive(Debug, Clone, PartialEq)]
pub struct LeadEndpoint {
pub owner: Id,
pub tip: Position,
pub stub: Position,
pub blockers: Vec<LeadBlocker>,
/// Separate information only; not part of the router's early lead guard.
pub stub_containers: Vec<LeadBlocker>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct LeadIncompatibility {
pub edge: Id,
pub source: Vec<LeadEndpoint>,
pub target: Vec<LeadEndpoint>,
pub allowed_pair_count: usize,
pub lead_clear_pair_count: usize,
}
fn blocker(r: &Rect) -> LeadBlocker {
LeadBlocker {
id: r.id,
bounds: RoutingBounds {
position: pos(r.left, r.top),
size: Size {
width: r.right - r.left,
height: r.bottom - r.top,
},
},
}
}
fn describe(owner: Id, endpoint: Endpoint, obstacles: &[Rect]) -> LeadEndpoint {
LeadEndpoint {
owner,
tip: endpoint.point,
stub: endpoint.stub,
blockers: obstacles
.iter()
.filter(|r| r.id != owner && r.crosses(endpoint.point, endpoint.stub))
.map(blocker)
.collect(),
stub_containers: obstacles
.iter()
.filter(|r| r.contains(endpoint.stub))
.map(blocker)
.collect(),
}
}
/// Return only edges for which every allowed endpoint pair fails the router's
/// existing mandatory-lead guard. Empty output is NECESSARY ONLY: it does not
/// establish a clear route, clear pins, successful search, or label clearance.
/// Uses the supplied final projection; does not modify the Project or choose
/// different ports/attachments. Stub containment is reported separately and
/// does not change the lead guard or its historical pinned/degenerate behavior.
pub fn lead_incompatibilities(
project: &Project,
diagram: &Diagram,
view: &ProjectedView,
) -> Vec<LeadIncompatibility> {
let nodes: BTreeMap<_, _> = view.nodes.iter().map(|n| (n.id, n)).collect();
let rectangles: Vec<_> = nodes.values().map(|n| Rect::node(n)).collect();
let authored: BTreeMap<_, _> = diagram.routes.iter().map(|r| (r.edge, r)).collect();
let headers: BTreeMap<_, _> = nodes
.values()
.map(|node| {
(
node.id,
if diagram.projection.state_machine().is_some() && !node.collapsed {
projection::state_header_height(project, node.element)
} else {
HEADER
},
)
})
.collect();
let mut ordered: Vec<_> = view.edges.iter().collect();
ordered.sort_by_key(|e| e.id);
let mut result = Vec::new();
for edge in ordered {
let (Some(source), Some(target)) = (nodes.get(&edge.source), nodes.get(&edge.target))
else {
continue;
};
let (_, _, attachments) =
effective_route(project, diagram, edge, authored.get(&edge.id).copied());
let ends = edge_endpoints(project, diagram, edge, source, target, view, attachments);
let obstacles = edge_obstacles(edge, &nodes, &rectangles, &headers);
let coincident = edge.source == edge.target
&& ends[0].len() == 1
&& ends[1].len() == 1
&& ends[0][0].point == ends[1][0].point
&& ends[0][0].stub == ends[1][0].stub;
let mut allowed_pair_count = 0;
let mut lead_clear_pair_count = 0;
for &a in &ends[0] {
for &b in &ends[1] {
if !allowed_endpoint_pair(edge, a, b, coincident) {
continue;
}
allowed_pair_count += 1;
if lead_pair_clear(edge, a, b, &obstacles) {
lead_clear_pair_count += 1;
}
}
}
if lead_clear_pair_count == 0 {
result.push(LeadIncompatibility {
edge: edge.id,
source: ends[0]
.iter()
.map(|&e| describe(edge.source, e, &obstacles))
.collect(),
target: ends[1]
.iter()
.map(|&e| describe(edge.target, e, &obstacles))
.collect(),
allowed_pair_count,
lead_clear_pair_count,
});
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn coincident_selfloop_exception_and_stub_containment_remain_separate() {
let owner = Id::from_u128(1);
let edge = ProjectedEdge {
id: Id::from_u128(2),
source: owner,
target: owner,
source_port: None,
target_port: None,
trace: false,
oriented: true,
};
let endpoint = Endpoint {
point: pos(0., 0.),
stub: pos(18., 0.),
};
assert!(!allowed_endpoint_pair(&edge, endpoint, endpoint, false));
assert!(allowed_endpoint_pair(&edge, endpoint, endpoint, true));
let obstacles = [Rect {
id: owner,
left: -1.,
right: 20.,
top: -1.,
bottom: 1.,
}];
assert!(lead_pair_clear(&edge, endpoint, endpoint, &obstacles));
let diagnostic = describe(owner, endpoint, &obstacles);
assert!(diagnostic.blockers.is_empty());
assert_eq!(diagnostic.stub_containers.len(), 1);
// This diagnostic must not be folded into the historical early guard.
assert_eq!(diagnostic.stub_containers[0].id, owner);
}
}
-238
View File
@@ -1,238 +0,0 @@
use oa_core::{projection, routing, *};
struct Fixture {
p: Project,
d: Id,
edge: Id,
source: Id,
target: Id,
blocker: Id,
}
fn fixture(ports: bool, gap: f32) -> Fixture {
let mut p = Project::empty();
let kind = if ports {
Kind::Function
} else {
Kind::DataType
};
let a = p.add_element(kind, Layer::Sa, "Source", None).unwrap();
let b = p.add_element(kind, Layer::Sa, "Target", None).unwrap();
let c = p.add_element(kind, Layer::Sa, "Blocker", None).unwrap();
for element in p.elements.values_mut() {
if let Some(SharedBody::DataType { definition, .. }) = element.shared_mut() {
*definition = DataTypeDefinition::Record { supertype: None };
}
}
let edge = p.relate(
if ports {
RelationKind::FunctionalExchange
} else {
RelationKind::DataAssociation
},
"Flow",
a,
b,
);
let d = p.ensure_diagram(Layer::Sa);
let source = p.place(d, a, Position { x: 0., y: 0. });
let target = p.place(
d,
b,
Position {
x: 500.,
y: 180. + gap,
},
);
let blocker = p.place(d, c, Position { x: 500., y: 20. });
for n in p.diagrams.get_mut(&d).unwrap().nodes.values_mut() {
n.size = Size {
width: 224.,
height: 160.,
};
}
if ports {
for (owner, end, side) in [
(source, EdgeEnd::Source, PortAnchorSide::Right),
(target, EdgeEnd::Target, PortAnchorSide::Top),
] {
let port = routing::semantic_port_endpoint(&p, edge, end).unwrap();
p.diagrams
.get_mut(&d)
.unwrap()
.nodes
.get_mut(&owner)
.unwrap()
.port_anchors
.push(PortAnchor {
port,
side,
offset: 0.5,
});
}
}
validate_candidate(&p).unwrap();
Fixture {
p,
d,
edge,
source,
target,
blocker,
}
}
fn report(f: &Fixture) -> Vec<routing::LeadIncompatibility> {
routing::lead_incompatibilities(
&f.p,
&f.p.diagrams[&f.d],
&projection::project_view(&f.p, f.d),
)
}
fn attachment_route(edge: Id) -> EdgeRoute {
EdgeRoute {
edge,
source_attachment: Some(EdgeAttachment {
side: PortAnchorSide::Top,
offset: 0.25,
}),
target_attachment: Some(EdgeAttachment {
side: PortAnchorSide::Bottom,
offset: 0.75,
}),
waypoints: vec![Position { x: 300., y: 400. }],
label: None,
}
}
#[test]
fn exact_twenty_gap_is_blocked_thirty_plus_clears_without_mutation() {
let f = fixture(true, 20.);
let original = f.p.clone();
let r = report(&f);
assert_eq!(r.len(), 1);
assert_eq!(
(
r[0].edge,
r[0].allowed_pair_count,
r[0].lead_clear_pair_count
),
(f.edge, 1, 0)
);
assert_eq!(r[0].source[0].owner, f.source);
let end = &r[0].target[0];
assert_eq!(end.owner, f.target);
assert_eq!(end.tip, Position { x: 612., y: 200. });
assert_eq!(end.stub, Position { x: 612., y: 182. });
assert_eq!(end.blockers.len(), 1);
assert_eq!(end.blockers[0].id, f.blocker);
assert_eq!(
end.blockers[0].bounds,
routing::RoutingBounds {
position: Position { x: 488., y: 8. },
size: Size {
width: 248.,
height: 184.
},
}
);
assert_eq!(end.stub_containers, end.blockers);
assert_eq!(f.p, original);
assert!(report(&fixture(true, 30.)).is_empty());
assert!(report(&fixture(true, 31.)).is_empty());
}
#[test]
fn semantic_manual_ports_override_dormant_route_attachments_and_pins() {
let mut f = fixture(true, 20.);
let expected = report(&f);
f.p.diagrams
.get_mut(&f.d)
.unwrap()
.routes
.push(attachment_route(f.edge));
assert_eq!(report(&f), expected);
let view = projection::project_view(&f.p, f.d);
let routed = routing::route_diagram(&f.p, &f.p.diagrams[&f.d], &view);
assert_eq!(
routed.edges[&f.edge].points.last(),
Some(&expected[0].target[0].tip)
);
assert!(
routed.edges[&f.edge]
.warnings
.contains(&routing::RouteWarning::NoClearPath)
);
}
#[test]
fn unconstrained_nonport_alternative_is_not_hard_blocked() {
let mut f = fixture(false, 20.);
assert!(report(&f).is_empty());
let mut route = attachment_route(f.edge);
route.source_attachment = Some(EdgeAttachment {
side: PortAnchorSide::Right,
offset: 0.5,
});
route.target_attachment = Some(EdgeAttachment {
side: PortAnchorSide::Top,
offset: 0.5,
});
f.p.diagrams.get_mut(&f.d).unwrap().routes.push(route);
let r = report(&f);
assert_eq!(r.len(), 1);
assert_eq!(r[0].allowed_pair_count, 1);
assert_eq!(r[0].target[0].blockers[0].id, f.blocker);
}
#[test]
fn nested_endpoint_body_is_traversable_and_promoted_attachments_are_suspended() {
let mut f = fixture(false, 20.);
// DataType containment is not required for this routing-only view witness:
// construct the supplied projected forest explicitly, retaining real owners.
let mut view = projection::project_view(&f.p, f.d);
let parent = Id::new_v4();
let source = view.nodes.iter_mut().find(|n| n.id == f.source).unwrap();
source.visual_parent = Some(parent);
source.position = Position { x: 40., y: 100. };
let element = source.element;
view.nodes.push(projection::ProjectedNode {
id: parent,
element,
position: Position { x: 0., y: 0. },
size: Size {
width: 300.,
height: 300.,
},
visual_parent: None,
depth: 0,
collapsed: false,
allocation_summary: false,
});
let mut route = attachment_route(f.edge);
route.source_attachment = Some(EdgeAttachment {
side: PortAnchorSide::Right,
offset: 0.5,
});
route.target_attachment = Some(EdgeAttachment {
side: PortAnchorSide::Top,
offset: 0.5,
});
f.p.diagrams.get_mut(&f.d).unwrap().routes.push(route);
let r = routing::lead_incompatibilities(&f.p, &f.p.diagrams[&f.d], &view);
assert_eq!(r.len(), 1);
assert!(
r[0].source[0].blockers.is_empty(),
"Ancestor body must not block source lead"
);
// Promotion changes actual projected owner: custom attachments no longer apply.
view.edges
.iter_mut()
.find(|e| e.id == f.edge)
.unwrap()
.source = parent;
let with_dormant = routing::lead_incompatibilities(&f.p, &f.p.diagrams[&f.d], &view);
f.p.diagrams.get_mut(&f.d).unwrap().routes.clear();
assert_eq!(
with_dormant,
routing::lead_incompatibilities(&f.p, &f.p.diagrams[&f.d], &view)
);
}
@@ -10,11 +10,6 @@ async fn press_escape(mounted: &mut Mounted, app: &mut App) -> Vec<Message> {
std::slice::from_ref(&input),
mouse::Cursor::Unavailable,
);
assert_eq!(
statuses,
[iced::event::Status::Captured],
"the mounted picker must capture Escape before App subscriptions"
);
crate::app::escape::tests::subscriptions(app, input, statuses[0], &mut messages);
for message in messages.iter().cloned() {
let task = app.update(message);
@@ -46,11 +41,17 @@ async fn mounted_state_missing_picker_escape_preserves_exact_document_then_reope
send(&mut app, Message::BehaviorDiagram(choice));
let mut mounted = Mounted::new(&mut app).await;
assert_eq!(state_edit::unplaced(app.project(), diagram), vec![f.b]);
// Locate the stable picker slot itself: selection controls may sit between
// it and the canvas. The single menu option opens below this slot.
let bounds = mounted.geometry(&app).bounds("state-missing-picker");
let picker = bounds.center();
let option = iced::Point::new(picker.x, bounds.y + bounds.height * 1.5);
let focus_id = iced::advanced::widget::Id::from("diagram-keyboard-owner");
let (_, canvas, _) = mounted
.geometry(&app)
.focused
.into_iter()
.find(|(id, _, _)| id.as_ref() == Some(&focus_id))
.unwrap();
// The existing picker is immediately above the measured canvas, separated
// by 8px. Its 12px text and 8px padding give a 31.6px row.
let picker = iced::Point::new(canvas.center_x(), canvas.y - 24.);
let option = iced::Point::new(picker.x, canvas.y + 8.);
let before = app.document.snapshot();
let original = app.project().clone();
let source = app.document.bundle().clone();
+1 -1
View File
@@ -187,7 +187,7 @@ pub fn view<'a>(app: &'a App, machine: Id, mut out: Column<'a, Message>) -> Elem
.into();
out = out.push(
column![
container(missing_controls).id("state-missing-picker"),
missing_controls,
selection_controls(app),
crate::diagram::focus::wrap(
canvas.map(event),
-98
View File
@@ -498,101 +498,3 @@ editing remains separate from semantic reconnect. The [decision and evidence
map](edge-attachments-20260922.md) records alternatives, lifecycle rules,
independent falsifiers, evaluators and the Process/Scenario applicability limits.
This is branch-specific work; it does not establish an integrated release.
## Retain released routing after independent corpus comparison — 2026-09-25
Issue #32's [fixed comparison](experiments/routing-independent-20260925/results.md)
rejects adoption of target-join J and bounded-lane L at this checkpoint. Optimized
timings pass the declared screen, but a fixed edge-ID permutation worsens shared
runs under both candidates; workshop label conflicts also increase. L's large
workshop overlap improvement does not establish native traceability. Keep released
`715036e` routing for the separate explicit Arrange-reset candidate. Preserve the
experiments and stop tuning this corpus. Reconsider adoption only with meaningful
named trace-task improvements, no newly ambiguous task, and appropriate runtime
evidence. This is a branch-specific decision, not a completed Arrange feature or
integrated release; the linked record retains rejected alternatives and limits.
## Placement must respect derived ports and mandatory exits — 2026-09-25
Branch-specific issue32 research, not an integrated release. The bounded
[placement comparison](experiments/connection-layout-reference-20260925/results.md)
shows that a node/label layout followed by independent port selection and routing
is not a faithful transfer of a port-constrained engine result. Automatic ports
change sides/slots after positions move even though authored anchors stay exact.
The sparse reference's20-unit gap cannot contain the released router's18-unit
port lead plus12-unit obstacle clearance. The sole endpoint pair is rejected
before path search; increasing search work would not repair that placement.
Keep both candidates experimental. A future candidate needs explicit final-port
and mandatory-lead compatibility checks, compound/undirected semantics, and the
existing preservation/native trace gates. Raw engine paths avoiding uninflated
node interiors do not prove compatibility with our inflated obstacles and leads.
Do not silently shorten those leads, move authored anchors, or persist external
generated bends to make a comparison pass. Revisit engine integration only with
a faithful geometry interface and observed usability benefit.
## Lead compatibility does not establish layout quality — 2026-09-25
The [bounded separation experiment](experiments/placement-clearance-20260925/results.md)
at07405126 fixes the exact sparse mandatory-lead conflict by moving eight nodes
down11 units. It removes NoClearPath and node penetration while preserving model
records, anchors and repeated-call stability. Existing route-control output is
byte-identical to released routing. However crossings20→22, shared length666→761
and label/stroke intersections0→1 prevent a general readability improvement
claim. Keep this flat-only repair isolated; do not connect it to production
Arrange or increase its rounds to tune away the result. Use actual endpoint
compatibility as a necessary placement constraint in a future initial coordinate
assignment with connection ordering and corridor/label space. Compound geometry,
automatic side changes and native tracing remain separate required evidence.
This is branch-specific experimental evidence, not an integrated capability.
## Keep cyclic groups coherent before assigning global ranks — 2026-09-25
The [SCC placement experiment](experiments/scc-placement-20260925/results.md)
at `2426d286` supports condensation of sibling-subtree cycles as a useful
structural step. Independent reconstruction finds four ten-node components in
the sparse case. Compact blocks remove the old layered prototype's shared top
corridor: raw pairwise sharing falls from 40,522 to 32, with fewer crossings and
less area than that prototype. The released router is unchanged. The full
comparison includes original and Arrange-reset controls; this is not a universal
improvement across all measures or scenes.
Preserve effective geometry at the placement-transfer boundary. An old
projected size can depend on children that subsequently move inward; retaining
the old authored size then loses an explicitly requested minimum. The corrected
example importer makes one conditional simultaneous minimum restoration and
still demands exact final projection. All 14 frozen cases now complete; the
13 prior successful outputs remain exactly unchanged, with conservation,
roundtrip and ten-call checks recorded. This is an experimental transfer
contract, not a production command or history integration.
Do not adopt the whole candidate yet. The two-container case still ignores
external-neighbor order within each parent and is worse than the old layered
zero-sharing witness. Sparse residual label conflicts, folded route retracing,
bipartite sharing and area tradeoffs remain distinct issues. The next bounded
comparison should preserve coherent SCC ranks while using actual cross-boundary
neighbors to order siblings. Treat label association separately from route
sharing, preserve the full quality vector, and retain native tracing as a later
acceptance gate. No global gap or routing-penalty sweep follows from this result.
## Incoming boundary order is useful but not sufficient — 2026-09-25
The [boundary-order comparison](experiments/boundary-order-20260925/results.md)
at3e21c1bc preserves SCC blocks/ranks and orders same-rank child blocks using
incoming external source centers. Dependency components provide deterministic
propagation; cycles use one simultaneous snapshot. It fixes the declared
simple two-container tracing witness (sharing164→0) and three-parent chain,
while preserving all ten flat Projects/metrics exactly. All20 candidates pass
independent full-Project conservation. Native saved-Project inspection confirms
the simple trace improvement without establishing a native planner integration.
Retain the mechanism experimentally. Folded workshop sharing726.5→1077.5,
expanded crossing6→7, and anchored/local-SCC label intersections prevent
unconditional adoption. Native anchored labels remain readable while their
backgrounds interrupt the parent border: geometric collision counts require
severity and ownership interpretation, not silent removal. Full member displacement
must be checked in f64 before final f32 rounding; checking only a rounded delta
misses large-origin errors. No further parameter sweep or release change is
justified by this checkpoint. Production selection, label handling and integration
remain open; the user requested a stop after publication.
+2 -12
View File
@@ -9,8 +9,7 @@ excluded by the user's explicit request, including after networking recovers.**
## Assembled source and acceptance boundary
Combined code through **4deced53b98cd4d7649ba7aa60fa4b9b30d2f3b8**, plus the
test-only import correction from **7c2b06b63f8a0fe14b3f001996bdf965b36a4e85**, adds the reviewed
Combined code **4deced53b98cd4d7649ba7aa60fa4b9b30d2f3b8** adds the reviewed
Connection/Route early-admission correction to the assembled Scenario/Text,
ordinary/State/Process/Allocation selection, direct drawing, Traceability and
picker changes. The [source handoff](prerelease-integrated-source-20260924.md)
@@ -22,16 +21,7 @@ claim combined Cargo, native, packaged or release acceptance. The independent
further material source defect in its stated scope. A subsequent peer compile
found a missing `projection::` qualification in the new Route test helper;
the current code includes that one-line correction. The original compile failed
before running tests. The first combined compile at `897d9f04` subsequently
found a missing `text_editor` import in the Allocation Text Apply regression;
the current source includes that one-line correction too. Both failures remain
recorded in the source handoff. The subsequent full test run at `8ddfadf4`
failed the mounted State picker fixture: added selection controls invalidated
its canvas-relative clicks. Source successor `a9cd364eacbbffa0693bab05b5a2b65f9d105535`
measures an identified fixed-height picker slot and checks Escape capture,
retaining the exact preservation/reopen/Place/Undo assertions. The source
handoff links the preserved failed and interrupted attempts. Corrected combined
Windows execution and package acceptance remain pending.
before running tests. Combined execution remains pending.
Live build, final-source and publication results belong in
[issue37](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/37).
@@ -1,160 +0,0 @@
# Automatic layout investigation
Issue [32](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/32)
owns scope, ownership, milestones and integration status. This is an experiment
record above released `715036e132677dd2bc2fb37ed316d93dc9987aec`, not an accepted
replacement layout contract or a completed fix. User-owned requirements remain
in `PROJECT_GOAL.md` and the issue.
The [first executed experiment](experiments/auto-layout-20260925/results-01.md)
records nine Windows fixtures at `e7deea70`: hierarchy/label improvements,
repeat stability, and two shared-connector regressions. The candidate remains
experimental; successful execution is not acceptance of a replacement command.
The [target-join experiment](experiments/auto-layout-20260925/results-j.md)
isolates a routing score correction with fixed Projects/nodes/ports/endpoints.
Its 185 regression checks pass, but an original-scene overlap regression and
additional bipartite T contacts prevent a general readability acceptance.
The [completed scoring/lane comparison](experiments/auto-layout-20260925/results-lanes.md)
records J/P/PL/L and closes this fixture-tuning experiment. L passes 188 selected
checks and strict core Clippy, but residual ambiguity and a runtime cost signal
require broader, independently selected evidence before production adoption.
The [frozen independent corpus comparison](experiments/routing-independent-20260925/results.md)
passes its optimized timing screen but exposes additional ID-order and label
tradeoffs. Retain released routing for the separate route-reset work; J/L remain
experiments without native traceability acceptance. Its complete inputs, raw
receipts, corrected evaluator and independent reviews are recorded together.
## Question and existing evidence
Can explicit Auto-layout produce a readable arrangement that accounts for
connections and their labels, including removal of stale bends, while preserving
semantic endpoints, containment/allocation, source parity and reversible editing?
The current `session::layout` sizes the containment forest, sorts roots using
directed edges and alias tie breaks, places four roots per row, and translates
authored route points only when both actual endpoints move equally. Its authored
route preservation is deliberate and tested in `tests/release_routing.rs` and
`tests/state_diagrams.rs`; the user's requested automatic bend replacement needs
an explicit amendment, not a silently weakened test.
The [source map](experiments/auto-layout-20260925/source-evaluator-map.md)
identifies the actual callers and preserved input/source/API contracts. The
[primary-source research](experiments/auto-layout-20260925/research.md) compares
Sirius/Capella workflows, ELK and reuse of the existing Rust router. The
[candidate critique](experiments/auto-layout-20260925/candidate-critique.md)
records unresolved design gaps before any production choice.
The existing `routing` module already supplies bounded deterministic orthogonal
search, node/header obstacles, fixed semantic port endpoints, crossing/shared-run
costs and automatic label collision search. Automatic elbows are derived, not
persisted. The investigation should reuse this capability unless experiments
show a concrete reason to replace it. Process topology rendering is a different
path; its reported overlapping routes do not alone prove an Auto-layout defect.
## Candidate decisions, not yet accepted
Compare these materially different choices against visible route/label quality,
semantic conservation, predictable user control, runtime/dependency cost,
determinism, model size and maintainability:
1. Retain node arrangement and only reset effective visible route/label constraints.
This is a useful control, but cannot by itself optimize poor node ordering.
2. Use a hierarchy-aware layered node arrangement and the existing router, with
label-aware spacing and bounded crossing-reduction sweeps. Explicit Auto-layout
can replace effective visible pins/label offsets; ordinary drag keeps its
existing preservation rules. This is a candidate, not a chosen implementation.
3. Adopt a mature external layout engine, accounting for ports, labels, nested
containers, runtime packaging and coordinate conversion. Evidence must justify
the integration/dependency cost over reusing the current router.
Open contract questions include hidden/folded routes, authored attachment and port
anchors, undirected and cyclic graphs, nested cross-boundary edges, repeated
layout stability, and the observable treatment of exhausted search/poor results.
No option may change semantic endpoints, ownership, allocation, expressions,
relation kind or source identity to improve a drawing. Other views must remain
unchanged, and one Undo on clean input must recover the complete pre-layout
project. Existing application behavior applies an unrelated pending property
draft first; that separate Apply is not silently folded into Layout's history.
The initial experiment retains the current command as the baseline and compares
reset-only with a layered prototype isolated under `examples/auto_layout_probe`.
Neither prototype changes production behavior. Effective reset eligibility must
come from the pre-layout projection and actual endpoint identities; merely being
drawn does not make a promoted route's dormant metadata eligible. Explicit label
reset means both fraction and offset, while semantic text and endpoint/port
attachments remain fixed. Production adoption remains conditional on the
critic's hierarchy, stability, direction, measurement and global-work checks.
The first [probe recipe](experiments/auto-layout-20260925/probe-notes.md) covers
nine small SA FunctionalDataflow fixtures. Its [independent source review](
experiments/auto-layout-20260925/probe-review.md) found no blocker to that finite
diagnostic run and lists important evaluator limitations. After that review,
the parent inspected the added ten-call prototype stability loop and formatted
the examples; the loop reports every differing/error result without a quality
pass. No production file was changed. The experiment intentionally does not
establish folded/filtered, State, Allocation, source-bundle or native acceptance.
## Evaluator before implementation
Use independently specified small graphs and real project views. Separate proper
crossings, collinear shared runs, obstacle collisions, label/card collisions,
label/label collisions, routing warnings, bends, length and occupied area. A low
crossing count alone can hide coincident edges or enormous drawings. Exempt only
explicitly documented intentional containment and common endpoint geometry;
never discard a failure because it is inconvenient to the proposed algorithm.
Compare the current command and the reset-only control before choosing a design.
Include a chain longer than the current four-column row, diamond/bipartite cases,
nested cross-boundary exchanges, stale authored detours/labels, fixed ports,
cycles/self-loops and disconnected components. Check deterministic repeat calls,
idempotence, model/source round trips and complete Undo/Redo. A probe is evidence
about its named fixtures, not universal graph quality or native usability.
Actual representative Windows workflows, including meaningful window/zoom sizes,
selection and saved reopen, follow an implemented candidate. Linux remains
excluded by the current user instruction. The separately published State label
candidate in issue36 is not silently treated as integrated into this base.
## Placement/reference compatibility checkpoint
The [fixed external placement comparison](experiments/connection-layout-reference-20260925/results.md)
tests the old native prototype and elkjs0.12.0 positions through the released
router on the same independent corpus. Mixed placement metrics improve, but
automatic ports differ from the engine's assumptions; the sparse candidate
violates mandatory port-exit clearance and falls back before path search.
Both workshop reference cases reject an unsupported undirected edge. Neither
candidate is adopted. The next interface must account for final automatic
ports and mandatory leads, not only node/label boxes. All results remain
branch-specific; Gitea holds publication and integration status.
The follow-up [mandatory-lead separation experiment](experiments/placement-clearance-20260925/results.md)
supplies that necessary check using the router's actual endpoint choices. One
bounded flat repair removes the sparse hard routing failure, but worsens crossing,
shared-run and label/stroke measures. Preserve the compatibility result without
adopting this repair as Arrange. Initial connection ordering and reserved routing/
label space, with compound handling, remain the next planner questions; more
repair iterations or router penalty tuning are not supported by this evidence.
The [coherent cyclic-group experiment](experiments/scc-placement-20260925/results.md)
then isolates the old native candidate's rank-stretching problem. Sparse sharing
falls from 40,522 to 32 with unchanged released routing. A corrected importer
preserves requested effective container minima after child movement; all 14
frozen cases complete and the 13 previously successful results remain exact.
This is useful structural evidence, not an Arrange replacement. Cross-boundary
child ordering, local label conflicts and folded backtracking remain explicit
witnesses. Source, failed/successful runs, conservation and independent reviews
are linked from the result. Gitea remains authoritative for live ownership and
publication status; no integrated checkpoint or release change is implied.
The [incoming boundary-order experiment](experiments/boundary-order-20260925/results.md)
resolves the exact simple two-container tracing defect and preserves all flat
SCC results. Twenty supported cases retain model/anchor/block invariants, but
workshop sharing/crossing and label tradeoffs remain. Saved-Project native
inspection confirms the simple benefit and limits the severity interpretation
of anchored label intersections. This is a published research checkpoint, not
an integrated Arrange replacement. Gitea records handoff and the user-requested
pause; no further experiment is authorized during that pause.
@@ -1,38 +0,0 @@
# #32 candidate critique — 2026-09-25
Read-only adversarial review of `harness/auto-layout-investigation-20260925.md` in the715036e-based isolated checkout, against the source/evaluator map. This critiques candidate choices; no implementation, execution or acceptance is claimed.
## Recommendation
Use the existing explicit **Command::Layout / Auto-layout / Arrange elements** operation for the new automatic behavior. The user specifically asks that operation to replace bends and consider labels/intersections. A second command/UI choice would preserve the obsolete behavior as a competing default without demonstrated need. Deliberately amend its documented contract and focused preservation tests, retain exact Undo, and retain existing ordinary drag/Arrange-next-drag contracts. A new command becomes warranted only if concrete compatibility/user workflows require both automatic policies, not merely because a test currently asserts old behavior.
Prefer comparing candidate1 reset-only against candidate2 layered siblings plus the existing router. No external engine is justified yet. The existing router already creates derived elbows, so reset does not require writing every solver corner as a persisted hard pin. Keep generated corners derived initially; the saved node placement plus remaining explicit attachments determines their repeatable reconstruction.
Recommended explicit Layout route contract: identify eligible visible, non-promoted edges from the **pre-layout projection**, remove their stored waypoints and label override (fraction and offset together), retain source/target attachments and node port anchors. Retain unrelated/hidden/promoted route records with existing equal-delta endpoint-owner translation. Do not call broad Reset routing if that also clears attachments. Preserve stable route-list order and remove an emptied record only under an explicit canonical no-metadata rule. Layout-generated record churn is not progress.
## Blocking design gaps before accepting candidate2
1. **Eligibility must be frozen once.** Visible edges, semantic endpoint-owner placements and promoted endpoints are different sets. Compute the reset set before node movement using projection visibility plus actual owner identity, not “every stored edge” or endpoints merely present in `d.nodes`. A filtered/hidden edge can retain a valid route; a folded edge may be drawn from an ancestor while its own route is suspended. Recomputing eligibility mid-layout risks erasing metadata when visibility/promotion changes. Small experiment: parallel visible/filtered edges, one folded child endpoint, and one both-endpoints-fold-to-same-anchor edge, all with distinctive pins/labels/attachments. Require only declared reset members to change, and retained pins to translate only through the existing owner-delta rule. Unfold/unfilter must reveal the retained custom route.
2. **Two forests are needed conceptually, not two model hierarchies.** The authored projection-parent forest includes folded descendants; the rendered topology may omit them. Reordering only rendered nodes can leave hidden children outside resized parents or leave future expand geometry broken. Conversely, expanding all hidden content for outer layout wastes space and ignores the actual view. Decide visible sibling arrangement versus hidden subtree placement/reservation explicitly. Lift each rendered inter-subtree edge to the relevant direct children at its lowest common ancestor; do not flatten every edge to roots (loses nested ordering) or count the same edge at every depth as independent demand. Small experiment: nested A/B children with crossed exchanges, folded A, external sibling C and a State entry/exit boundary. Check containment/header/port-footer rules before and after expand, with semantic parents/allocations exact.
3. **Idempotence will fail if spacing compounds current sizes.** Current measure uses each authored `node.size` as a lower bound. If label clearance expands a container and the next call adds the same margin again, repeated Arrange grows indefinitely. Label spacing based on previous routed bounds can similarly oscillate. Decide whether current sizes are immutable minima, or may shrink; the latter exceeds today's behavior and needs justification. Compute desired padding from content minima with `max`, not repeated addition to an already padded size. Small experiment: ten consecutive calls on nested long-label/parallel-edge fixtures, comparing full Projects after first vs second and sizes after tenth; repeat after Save/reparse. A two-call-only test can miss alternating period-two layouts.
4. **Cycle/direction policy is not settled by “stable sweeps”.** Some projected edges are undirected; direction may be semantic or merely an endpoint representation. Use directed topology where justified, deterministic SCC treatment for cycles, and explicit undirected ordering inputs. Do not arbitrarily make a Capability/Traceability edge's serialized orientation a mandatory rank. Freeze alias/identity tie rules; crossing sweeps require a stable acceptance tie-break to avoid ping-pong. Small experiment: directed diamond+return, reversed undirected endpoint records, self-loop, parallel/reversed edges and disconnected isolates. Permute input records; independently require identical output for identical IDs and stable quality under UUID changes (not necessarily identical coordinates under reidentification).
5. **Label reset and label-aware spacing need different evidence.** Clearing authored overrides is a reasonable explicit-auto interpretation but must be announced, since issue32 says “take into account” labels, not explicitly erase them. Retain semantic text/typed references; only the target view's override changes. A stale far-away label is a concrete reset fixture; an intentionally constrained attachment/label case tests whether residual collisions are honestly reported. Base715 label widths are scalar estimates, and State title/multiline geometry is known inaccurate without36. Do not tune spacing to claim accurate measured-State acceptance on715. First isolate ordinary/association labels; use conservative declared bounds for experiments, then rerun State B/W/U once36 integrates. Font-free core/API parity forbids quietly using desktop-only font results inside Command::Layout.
6. **Bounded sweeps do not alone bound runtime.** Each complete route evaluation invokes previous-edge interactions, node obstacles and label comparisons; repeated per-sibling trial routing can multiply this cost by nodes×sweeps. Lifting topology naively can multiply edges×depth. Define global deterministic work budgets for candidate ordering/scoring, not just a fixed iteration count, and retain the best valid candidate on exhaustion. Route only a bounded number of whole candidates; cheap crossing surrogates can rank candidates but final acceptance must inspect actual geometry. Small experiment: a fixed family increasing sibling count/edge density/nesting, recording candidate count, comparison/work counters and wall time; include no-edge/isolate cases so they do not pay quadratic routing costs. No hard latency threshold should be fabricated from one machine.
## Input/source/API contract checks
- Clean whole-view Layout should create one reversible model/source transaction. `app.rs` applies a pending property draft before executing Layout, potentially as a separate transaction; do not accidentally promise one Undo reverses both an unrelated draft Apply and Layout. Use a clean-input one-step Undo oracle and a separate valid/invalid pending-draft admission test. Keep diagram UUID remapping, stale selection handling and disabled/pending form policy.
- `prepare_command`/Document/source bundle/REST dry-run must produce the same Project for the same inputs without GUI fonts, caches or selection. A frontend-only rearrangement would fail this. Roundtrip the stored record representation, check unrelated source files/comments remain exact, and recover the exact old source/model with Undo—not merely visually similar positions.
- Keep Allocation Arrange-next-drag, ordinary group translation, semantic ports, reconnect, Hide/show, collapse flags and other diagrams unchanged. A route reset belongs only to explicit Layout. A failed candidate must not clear history or leave a partially reset diagram.
- Native validation later needs visible controls, Fit/export agreement, actual label containment and route readability, plus Save/reopen/Undo. Do not extend the implementation merely to expose a new State Auto-layout control before a demonstrated workflow need; shared State initialization still needs regression coverage.
## Smallest discriminating experiment set
Freeze six hand-built cases before implementation: (A) stale dogleg+far label with fixed attachments, (B) two-container reversed sibling connections with a known zero-crossing witness, (C) nested folded/filtered route-conservation sentinel, (D) cycle/self-loop/parallel/undirected variants, (E) long ordinary/association labels with feasible compact clearance, (F) dense bounded stress. Compare existing Layout, reset-only, and a layered prototype on the same independent vector: invalid overlap/penetration, label collisions, proper crossings, positive collinear overlap, turns, path length/stretch, area and routing warnings. Include ten-call idempotence, exact other-view/semantic conservation, source roundtrip and Undo/Redo.
Candidate2 earns selection only if it materially improves at least B/E over reset-only without regressing the hard invariants or bounded workload. A tie favors the smaller candidate. A nonplanar or contradictory-fixed-port fixture may retain crossings; zero-crossing-by-overlap, giant detours, hidden edges or clipped labels is not a solution. Failure on a named fixture should revise the exact layer/policy implicated, not trigger an automatic wholesale engine dependency.
@@ -1,56 +0,0 @@
"""Compare fixed Project/node/port/endpoint geometry and report routing changes.
Usage: python compare_probe.py OLD_JSONL NEW_JSONL NEW_OUTPUT_JSON
No layout-quality pass is inferred from equal inputs or successful execution.
"""
from pathlib import Path
import hashlib
import json
import sys
old_path, new_path, out = map(Path, sys.argv[1:])
def read(path):
rows = [json.loads(line) for line in path.read_text(encoding='utf-8').splitlines()]
return {row['fixture']: row for row in rows if 'fixture' in row}
old, new = read(old_path), read(new_path)
assert old.keys() == new.keys()
def variants(row):
yield 'before', row['before_project'], row['before']
yield 'baseline', row['after_project'], row['after']
for name in ['reset_only_control', 'experimental_candidate', 'manual_planar_order_witness']:
if row[name] is not None:
yield name, row[name]['project'], row[name]['metrics']
def endpoints(metrics):
return {e['id']: [e['points'][0], e['points'][-1]] for e in metrics['routed_edges']}
keys = ['proper_crossings', 'pairwise_collinear_shared_length',
'nonterminal_pairwise_shared_length', 'unrelated_node_collisions',
'unrelated_edge_node_penetrations', 'label_node_collisions',
'label_label_collisions', 'unrelated_label_stroke_intersections',
'warning_count', 'route_bends', 'route_length', 'drawing_area']
results = []
for name in old:
lhs, rhs = list(variants(old[name])), list(variants(new[name]))
assert len(lhs) == len(rhs)
for (variant, op, om), (other, np, nm) in zip(lhs, rhs):
assert variant == other
fixed = {'project':op == np, 'nodes':om['projected_nodes'] == nm['projected_nodes'],
'ports':om['projected_ports'] == nm['projected_ports'],
'route_endpoints':endpoints(om) == endpoints(nm)}
results.append({'fixture':name, 'variant':variant, 'fixed_geometry':fixed,
'metrics':{key:{'old':om[key], 'new':nm[key]} for key in keys},
'new_point_contacts':nm.get('point_contacts'),
'new_point_contact_details':nm.get('point_contact_details')})
summary = {'old_sha256':hashlib.sha256(old_path.read_bytes()).hexdigest(),
'new_sha256':hashlib.sha256(new_path.read_bytes()).hexdigest(),
'all_projects_nodes_ports_endpoints_exact':all(all(r['fixed_geometry'].values()) for r in results),
'scope':'Fixed-geometry comparison; quality vector retained, no aggregate quality pass.',
'results':results}
with out.open('x',encoding='utf-8') as f:
json.dump(summary,f,indent=2)
f.write('\n')
print(json.dumps({k:v for k,v in summary.items() if k != 'results'}))
for row in results:
if row['variant'] == 'experimental_candidate':
print(json.dumps({'fixture':row['fixture'], 'fixed_geometry':row['fixed_geometry'],
'changed_metrics':{k:v for k,v in row['metrics'].items() if v['old'] != v['new']},
'point_contacts':row['new_point_contacts']}))
@@ -1,46 +0,0 @@
# L results and four-way routing experiment audit
Recommendation: stop tuning these fixtures. L is a useful experimental witness that route alternatives affect sharing, but its small layered benefit and material runtime signal do not presently justify its per-leg preprocessing as a production default. Keep J as the simpler independently motivated scoring correction candidate; decide L only against frozen independent scenes and route-only timing. No production/native acceptance claimed.
## Verified final L result
Primary J06 pin `08656b18bf8934cf264469cf68fc6dea97c15cbb`; L11 pin `e8ec6dbb3160f62476a5557f14605f68959f65fe`. Both recorded offline dev/gnullvm probe commands exit0, source unchanged, failure null. Verified receipt log hashes. Separate raw-output traversal confirms all37 Projects, projected nodes/ports and per-edge endpoint records exactly equal. All nine candidate supported/repeat-input/idempotence/ten-call/JSON-and-single-source-roundtrip results remain true, with unchanged conservation and baseline history checks. Candidate Command/Undo integration remains absent.
J→L changed scalar rows only:
- Original bipartite raw sharing872→724, nonterminal800→652.
- Layered bipartite raw187→176, nonterminal115→104; drawing area175960→165360.
- Original two-container raw/nonterminal54→12.
- Two-container baseline and reset raw/nonterminal18→12 each.
The other32 rows are unchanged in recorded scalar quality metrics. No changed point-contact, proper-crossing, length, bend, warning or collision counts in J→L. Independently comparing full candidate metric objects confirms all nine L layered metrics exactly equal PL, not merely the headline totals. Remaining layered bipartite104 nonterminal shared units still prohibit a solved-traceability claim.
Test10 receipts record135+7+13+18+2+13=188 passed,0 failed/ignored, exit0, unchanged source. J02 and L10 command argv and entire recorded environment dictionaries compare equal. Their routing_geometry test summary elapsed4.30s versus16.43s (~3.82 times, +12.13s); parent reports no concurrent agent compiler. This is a material cost signal, not a controlled routing benchmark: suite runtime includes varied tests and scheduling effects, with no repeated route-only timing. It must not be dismissed by quoting cargo compilation time or presented as an established scaling law.
Verified37 L schematic image hashes/lengths and manifest input hash. Native/glyph rendering was not exercised. Strict Clippy12 was active when assigned and is outside this audit; no outcome inferred.
## Four-way conclusion
All numbers below are raw pairwise shared length; inspect the preceding audits for contacts/area/turn tradeoffs.
| Scene/variant | J | P | P+L | L |
|---|---:|---:|---:|---:|
| Layered bipartite |187|187|176|176|
| Original bipartite |872|730|724|724|
| Baseline/reset bipartite |276|276|72|276|
| Original two-container |54|6|12|12|
| Baseline/reset two-container |18|18|12|12|
P has no layered benefit. P+L's baseline bipartite72 means only common terminal sharing remains, but proper crossings rise0→1, length+24 and area+19392; L alone does not produce that tradeoff. The strongest ordinary two-container sharing result is P6, at an extra bend,12 length units and one T contact. Neither the coefficient nor lanes dominates all vectors. J diamond's isolated improvement remains valid but does not erase its original bipartite regression.
Next scope should be finite and specified before inspecting outcomes: one realistic nested/folded scene, one mixed fan-in/out with a fixed edge-ID permutation, and one modest sparse scene measured by route-only timing and warning/budget counts. Preserve endpoint/model constraints and evaluate traceability, collisions, bends/length/area jointly. Do not silently extend unsupported layered folded behavior into an acceptance claim. Set practical timing and readability criteria before repeating improvement. If L does not show proportionate independent benefit, omit it; avoid adding configuration/architecture solely to retain every experiment. The explicit Layout reset policy and ordinary input/Undo/Save lifecycle are still separate implementation work.
## Evidence identities
J06 output `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
L11 output `64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d`.
L11 result.json `feee84c2fde115c22ea865033ff2d136da2aace1f1c8a7423c8add11358366a8`.
L comparison JSON `e1e23e6c2a50cd384457bb061d5b70a740f586f42767164fad9703ecbb4096a8`.
L contact audit JSON `6f6cc674c27d3f43001fe1751ef3b09332caa9ddca396759f5525f811cbe1aaf`.
Read-only audit of completed records; no build/probe/helper rerun, source edit or publication. Earlier independent J/P/PL source/results notes retain grid-axis, subdivision-score, capped retained coordinates versus unbounded preprocessing, stable-edge-order and approximate-label limitations.
@@ -1,20 +0,0 @@
# Bounded L lane-candidate source review
Reviewed routing.rs SHA256 `af5995af10c8e3b30c5c6fb776a2ac2678eeef59dd58eb0cdb3d5c62cd153f1b` before parent formatting. Static inspection only; no builds or source edits. No blocking implementation finding for the finite nine-fixture P+L / J+L probe comparison.
The code retains all sorted base obstacle coordinates and adds at most64 unique extras EACH axis (128 total), filters nonfinite generated values, deduplicates before ranking, then ranks distance from the start/end axis interval, distance from its midpoint, and numeric value. Final lists return to coordinate order. It derives perpendicular offsets only from nondegenerate settled other-edge segments. The current edge's earlier legs/source stub still contribute occupied scoring but do not generate lanes. Fast/grid receive the identical per-leg RoutingSpace; obstacles, endpoints, authored pins, terminal joins and fallback remain unchanged.
Three new tests cover80 retained base coordinates plus64 extras per axis, previous-segment reorder/duplication invariance, nearest-interval/midpoint selection and nonfinite rejection, and direct calls to fast/grid sharing the same parallel-lane witness. The latter expects min(direct cost,272) and supports both coefficients. No test success is inferred before execution.
Test-scope caveat sent to parent: the existing `unspecified_continuation_keeps_intermediate_leg_choice` test deliberately hardcodes baseline coefficient0.12, path choice and cost255.52. At P3, the shared penalty caps80 and the alternative is cheaper; a whole private suite at P3 can fail that baseline-policy assertion. Preserve the result honestly; restore0.12 for baseline-suite claims or explicitly distinguish experimental tests. This does not block a diagnostic P+L probe.
Limits relevant to interpreting results:
-64 bounds retained coordinates, not scan/sort work. Every endpoint-pair/leg constructs candidates from all previous segments; this preprocessing is outside the search-step budget. No large-scene performance guarantee.
- Added coordinates can make the grid exceed65536 cells even when its original grid fit. Existing exhaustion warning/fallback is the evidence to inspect, not something to suppress.
- Grid scoring is coordinate-subdivision-sensitive: strict-interior crossing tests can miss contacts at inserted grid vertices, and per-segment capped overlap charges can change with subdivision. Therefore a grid result can change due to scoring partition as well as newly offered parallel lanes. Keep independent contact/shared-interval metrics authoritative for quality observations.
- Rank uses one axis and does not filter segment extent on the other; remote lanes can consume the cap. This deterministic heuristic is not proof of optimal lane coverage. The router still uses a feasible fast path before grid, two-axis rather than signed-direction search state, stable sequential edge order, and local hard-pin legs.
Required experiment interpretation: compare P+L to P and J+L to J with exact Project/node/port/endpoints, all quality metrics and warning counts. Retain label collisions, T/bend contacts, length/turn/area regressions; fewer shared units alone is not acceptance. No broad production or native readability conclusion follows from this finite source review.
Current formatted routing SHA256: 3a8af7a44f8f32bd9fb94dddd9184fafcf64c93c510025169c62958566bbaedf. Reread formatted lane construction: filtering/ranking/cap semantics agree with reviewed candidate. No mechanical original-byte whitespace comparison claimed. Parent plans exactly the three lane-filtered private tests for P+L, then restores0.12 for the full baseline suite; that appropriately separates the baseline-policy assertion noted above.
@@ -1,35 +0,0 @@
# P+L results independent audit
P+L demonstrates that additional lanes can remove one scene's nonterminal overlap, but adds a proper crossing and gives only a small layered improvement. It does not yet justify adopting the extra heuristic as a general production default. Static record audit only; no reruns, builds or source edits.
Compared P07 `3d7adff923dee5bed54dfdccc119dbee0c7c2773` with PL09 `d0be9ff0674373fcf9623daf62bbf50dad02c4df`. Both probe receipts exit0, failure null, unchanged source; all logged hashes independently checked. Separate raw-output traversal confirms all37 Projects, projected nodes/ports and route endpoint records exact. All nine candidate support/repeat/idempotence/ten-call/roundtrip results remain true; conservation and baseline Command::Layout history checks match P. Candidate Undo integration remains untested.
Test08 actually ran `cargo test --locked --offline -p oa-core --lib lane`: five passed,130 filtered, zero failed/ignored. This is three new routing lane tests plus two existing scenario-layout tests, not a whole core-suite pass.
All changed numeric-vector rows, P→PL:
| Scene/variant | Sharing raw / nonterminal | Other changes |
|---|---|---|
| bipartite before |730→724 /658→652|contacts10→9; bends5→4; length2076→2064|
| bipartite baseline |276→72 /204→0|proper crossings0→1; contacts6→5; length3284→3308; area300576→319968|
| bipartite reset |276→72 /204→0|same changes as baseline|
| bipartite layered |187→176 /115→104|area175960→165360; contacts9 unchanged|
| two-container before |6→12 /6→12|contacts3→2; bends5→4; length1524→1512|
| two-container baseline |18→12 /18→12|no other scalar change|
| two-container reset |18→12 /18→12|no other scalar change|
Remaining30 rows unchanged; eight other layered vectors unchanged. No new label-collision or warning-count changes appear. The baseline/reset proper crossing is a real quality tradeoff, not an automatic failure: a visible isolated crossing may be easier to trace than coincident routes. Conversely, zero proper crossings in the layered scene still accompanies104 nonterminal shared units. Two-container original sharing doubles6→12 despite fewer contacts/turns. No single scalar orders all these results.
Viewed the baseline and layered bipartite PNGs. Baseline channels separate except for the isolated crossing; layered channels retain shared horizontals. Verified all37 offline image hashes/lengths and manifest input binding. These are schematic core geometry, not actual font/native rendering or a user traceability test.
Performance/complexity: probe command elapsed approximately67.1s(P) and69.7s(PL), but these cargo invocations include compilation; they are not comparable routing benchmarks and establish no overhead bound. The new code scans/sorts all prior segments for each endpoint-pair/leg;64-per-axis limits retained coordinates, not preparation work. It can expand the grid past its existing cell cap. Grid crossing/overlap scoring also changes under coordinate subdivision. None of these limitations is resolved by the tiny fixture set.
Recommendation: finish the already-declared J/P/PL/L grid and stop coefficient/lane-spacing tuning on these fixtures. Retain L as an experimental option unless the final comparison supplies stronger value. The next useful acceptance scope is a frozen, modest set of independent scenes chosen before results: one realistic authored diagram with nested/folded content, one mixed-direction fan-in/out, and one moderately sized sparse diagram for routing time/budget behavior, including a fixed edge-order permutation. Choose a preferred traceability tradeoff explicitly; do not add architectural hooks merely to preserve this heuristic. Prioritize the explicit Layout command/reset contract and production integration lifecycle once a maintainable geometry choice is selected. No #32 closure or native readability acceptance follows here.
Bindings:
- P output SHA256 `13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
- PL output `04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd`.
- PL result.json `538aa79bcedd4cf646c63d5309ec738be4676e2045715db1035a4f334a536117`.
- PL comparison JSON `81f57e651a8840aaaeacc085df2eb90174b2e494182f6cd40ccd6d50e7bb531e`.
- PL contact audit JSON `60ce7e9735ceef50a92d29a0414aafe3d8fb6174dab99eff6397e2abc88e0afa` (inspected as independent worker evidence, not rerun here).
@@ -1,26 +0,0 @@
# P overlap-penalty experiment independent audit
Confirmed the reported finite result. Static read-only audit; no build, probe rerun, source edit or GUI action. P does not improve any of the nine layered candidate metric vectors and is not a demonstrated solution to their remaining shared routes.
Primary comparison: J06 `08656b18bf8934cf264469cf68fc6dea97c15cbb` versus P07 `3d7adff923dee5bed54dfdccc119dbee0c7c2773`. Inspected the latter commit: only routing.rs changes, overlap coefficient0.12→3.0 plus an experiment comment; cap80 remains unchanged. Both recorded `cargo run --locked --offline -p oa-core --example auto_layout_probe` receipts are Windows gnullvm/dev, exit0, inputs unchanged, failure null. Independently verified every log hash in both receipts.
Independent traversal of the raw outputs confirmed all37 variant Projects, projected nodes, projected ports and emitted route endpoint records match exactly. All nine layered candidates retain supported=true, repeat-input exactness, idempotence, passes2–10 equal first/previous, exact JSON/single-source roundtrips and identical conservation results. The authored-detour route-reset exception remains intentional. Baseline Command::Layout history/Undo checks remain identical; this is still not candidate-command Undo evidence.
Only two variant rows change numeric metrics:
| Original/before scene | Raw sharing J→P | Nonterminal sharing J→P | Bends | Length | Point contacts |
|---|---:|---:|---:|---:|---:|
| crossed_bipartite |872→730|800→658|4→5|2064→2076|9→10|
| two_containers_reversed_children |54→6|54→6|4→5|1512→1524|2→3|
Each extra contact is classified as a T contact in the separately generated independent interval audit: bipartite T3→4 and two-container T1→2; proper crossings remain0. Lower shared length therefore comes with one additional bend,12 length units and one additional point contact in each scene. Bipartite returns to the pre-J shared-length total; this does not establish trace readability. All baseline/reset rows, manual witness and nine layered scalar vectors are unchanged. Exact model/endpoint invariants do not imply identical polylines.
Evidence identities:
- J06 raw output `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f` (also identical to J03 output).
- P07 raw output `13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
- P07 result.json `6149122d05d77e02b463edb3dd359b06786bc4468c27d8cd625cbc1bc80c9894`.
- P comparison JSON `9f228fbe78e1888c5d93e87dddd8d2effc01bab723929a87423c61e23f5cad66`.
- P independent contact audit JSON `6f4add5c81f6d16c45efabbefd9e36c9beb637b6823993f0d51adc3e20485ad9`. Its recorded definitions and counts were inspected; this reviewer did not execute that helper again.
Recommendation: archive P as a bounded negative result for the layered overlap objective, preserving the two ordinary-scene tradeoffs. A predefined bounded lane-candidate experiment can now test whether available route geometry, rather than this single coefficient, limits improvement. Retain the same Projects/endpoints and all quality metrics; do not tune indefinitely against these nine fixtures or claim general quality/native acceptance. The cap, sequential edge order, fast-path preference, axis-only grid state and estimated label bounds remain limits.
@@ -1,47 +0,0 @@
# #32 bounded automatic-layout probe
Prepared `crates/oa-core/examples/auto_layout_probe.rs` in `.local/auto-layout-20260925` against reference source `715036e132677dd2bc2fb37ed316d93dc9987aec`. No production edits, compiler, Cargo, GUI or Gitea operation by this evaluator. Rustfmt parsed/formatted only the owned main example (`skip_children=true`). The separately owned `auto_layout_probe/layered.rs` is imported through its agreed `candidate(&Project, Id) -> Result<Project, ModelError>` interface; the evaluator does not use candidate internals to define fixtures, geometry metrics or expected conservation.
## Execution and output
From the worktree, in the parent's configured exclusive Windows toolchain environment:
```powershell
cargo run --locked --offline -p oa-core --example auto_layout_probe > auto-layout-probe.jsonl
```
The parent has `.local/run-auto-layout-check-20260925.py` for pinned receipt-based execution. Prefer that for recorded evidence; its source hash/commit must identify the actual build. The example's `reference_source` metadata is the investigation baseline, not a runtime attestation of checkout identity. Stdout is JSON Lines: one metadata/self-check record and nine fixture records. No output files, network calls or UI operations are performed by the example. Errors/unsupported candidates are explicit fields, not quality passes. There is no aggregate score or threshold; a zero metric is not a readability or hard-safety certification.
Each fixture emits the original and current `Command::Layout` Projects and real projected/routed geometry. It also emits the same observations for a **reset-only control applied after existing Layout**, and for the separately implemented experimental candidate invoked on the original Project. The control clears only waypoints and label placement on visible routed edges whose geometry is not suspended/promoted, retaining endpoint attachments, hidden/promoted records and empty route records. The candidate does not determine this control. Ten successive existing Layout calls and ten successive candidate calls are each compared with their preceding and first result, stopping with an explicit error if needed. Candidate identical-input repeat and one further application are also compared separately. Reset eligibility is measured after baseline Layout; the candidate freezes it before Layout. These all-visible fixtures do not change visibility, so broader eligibility-equivalence claims are deferred.
## Declared fixtures
1. Four-node flat chain, initially left to right.
2. Seven-node chain, initially left to right, exposing four-column row wrapping if present.
3. Diamond with branch/join semantics and declared two-level positions.
4. Crossed bipartite ordering, including both straight and crossed pairings.
5. Parent Function with two child Functions, internal exchange and exchange to an outside Function.
6. Two-node authored high detour with a far label offset; reset-only isolates stale constraint cost.
7. Two-node exchange with explicit source-Left0.3 and target-Right0.7 port anchors.
8. Two parent Functions, each with two children, and reversed inter-parent pairings. A separate predeclared witness swaps only right-child y positions, aligning each source with its target. Its real routing is measured; no zero-crossing result is assumed.
9. Three Functions with long ordinary exchange names, including a bypass; the actual existing summary/name excerpt bounds are observed.
Project, diagram, Function, placement, relation and automatically created port UUIDs are remapped to stable IDs in creation order. Port aliases are reset explicitly. Names and other aliases are unique per fixture, avoiding random-ID tie dependence. The fixture Projects in output allow independent repetition and offline visualization; projected node rectangles/ports and per-edge routed point sequences/label rectangles are also included.
## Metric definitions and exclusions
- **Proper crossings:** unique intersection locations per distinct edge pair, interior to both straight segments. Locations deduplicate at0.0001 world units. Segment endpoints, bend contacts, T junctions and collinear overlaps are excluded from this count. Raw crossings remain the primary count. A separate nonterminal count subtracts only contacts within `PORT_STUB` of a physically equal endpoint with the same projected owner, where both tested segments are terminal. Entire compacted first/last segments are never exempt.
- **Shared runs:** summed pairwise collinear overlap length, reported separately from crossings. Raw length is primary. Common exact endpoint terminal overlap gets a separately reported exemption bounded by `PORT_STUB` per common endpoint, capped by the overlap. Three overlapping edges contribute three pairwise overlaps; retraced segments may contribute multiplicity. This is not union length.
- **Unrelated node collisions:** positive rectangle intersection area for distinct nodes; ancestor/descendant pairs are exempt from this count. No inferred intent is attached to a reported collision.
- **Label/node collisions:** positive intersection of real routed label bounds with projected node rectangles, including endpoint nodes. A label wholly inside an endpoint ancestor's *body below the header* is exempt; overlap with its header remains reported. Ordinary header height is64; dedicated State height uses the core helper. Border crossings are retained. These conservative boxes are not glyph measurements.
- **Edge/node penetration:** per edge/node pair, positive clipped segment length in unrelated node interiors. Endpoint-owner nodes are exempt; endpoint ancestors contribute only their header obstacles, so intentional passage through container bodies/boundaries is not counted. This does not detect re-entry into an edge's own endpoint node.
- **Label/stroke intersection:** positive clipped length of another edge's stroke inside a label rectangle, one record per label-edge/stroke-edge pair. Own-edge strokes are excluded; an intentional anchor/label association is not declared a defect. Stroke thickness, arrowheads and antialiasing are unmodeled.
- **Other observations:** actual routing warnings and details; routed total length; direction-changing bends including reversal; total drawing bounding-box area (including labels/nodes); real node/port/edge geometry. Area is scale-sensitive and is not minimized at the expense of crossings or readability.
Tiny analytic assertions check proper crossing versus endpoint contact, collinear overlap versus separated lines, rectangle contact, and line/interior clipping. They will run with the example, but have not been executed by this author. Geometry tolerance is0.0001 world units, while proper-intersection parameter/parallel checks use1e-9.
## Conservation and limits
The current command is exercised through `Session`, with exact one-step Undo/Redo and history/no-op checks. Full JSON decode and formatted single-source parse round trips are compared to the complete Project before/after; these do not prove original multi-file comments/byte preservation. Semantic records, target-view nongeometry fields, other views, per-node identity/visibility/port anchors and authored routes are reported separately. Reset/candidate route equality may intentionally be false and must be assessed against their stated reset policy, not silently treated as semantic loss.
Folded/filter/hidden-route preservation is implemented in the reset eligibility check but not independently falsified by these nine fixtures. Dedicated State #36 native typography, dense stress, cycles, disconnected large sets, non-planar crossing lower bounds, self-crossings, self-loops, full stroke geometry and interactive cognitive load are absent. The candidate may explicitly reject unsupported cases. No algorithm can promise crossing-free output for arbitrary non-planar graphs; the paired-container witness only establishes a concrete alternative ordering to examine. Use vector observations and the output geometry to diagnose mechanisms before selecting a candidate; this is a bounded experiment, not a production layout-quality framework or native acceptance.
@@ -1,27 +0,0 @@
# #32 first diagnostic probe review
**No blocking finding for compiling/running the current finite experiment.** This is a source/evaluator-validity review, not production acceptance or a claim the candidate improves layout. Nine small deterministic FunctionalDataflow fixtures support a bounded comparison; later scope gaps should not delay this run. No compiler, GUI, helper, source edit or Gitea operation performed.
Reviewed snapshot SHA256: auto_layout_probe.rs `72d850fdd9aad65788004949380c28cba48a0c2be3dc28f3aef3900c7f8724c7`; auto_layout_probe/layered.rs `bda9a59968b4b0e284e8e1393eb86c90cdf0d856d5f9830ae3c6fc0043df839a`. The evaluator worker is separately finalizing candidate repetition reporting; later edits require a scoped diff check, not relabeling this reviewed snapshot.
## Evaluator validity
Raw strict-interior segment crossings and pairwise collinear shared length are primary outputs, with crossing coordinates deduplicated per edge pair. Endpoint sharing is not exempted wholesale: secondary figures subtract only bounded common physical tip lengths. Node/header, label/node, label/label and unrelated stroke/label measurements remain separate. Analytic primitive checks cover a proper crossing, endpoint touch, collinear overlap, disjoint parallel segments, rectangle touch and inside-length boundary. Complete before/after models and routed points are emitted, permitting independent examination beyond scalar totals. No quality threshold or automatic overall-pass field promotes a poor drawing to acceptance.
Fixture IDs are normalized before use; semantic port IDs/aliases are also stabilized. The manual reversed-child witness is separately authored and measured, not generated from candidate output. It must still be read as a witness with its reported validation/geometry, not an asserted universal optimum. Standard parse/JSON roundtrip and old-Layout history checks are meaningful within their named scope.
## Actionable limitations to retain when interpreting this run
1. **Reset control eligibility:** reset_effective_routes receives the already arranged Project, whereas layered candidate freezes its eligible set before Layout. For these all-visible, uncollapsed fixtures, Layout does not change membership/promotion, so this does not invalidate the current comparison. Freeze the original eligible IDs for future folded/filtered cases; do not generalize current equivalence.
2. **Conservation granularity:** semantic/other-view/node-metadata checks are independent and useful. target_view_nongeometry_exact restores all routes and layout before comparing; authored_routes_exact will intentionally become false. Those fields do not separately prove attachment preservation, invisible-route retention or a no-change layout field. Add targeted comparisons before making those claims on future fixtures. The current prototype source copies original route records and only clears eligible waypoints/labels, then translates retained routes, so no observed source-level violation was found here.
3. **History scope:** undo_exact/one_step_undo/redo_exact exercise existing Command::Layout through Session only. The layered candidate is a pure Project transformer, not an integrated command and has no tested operation/history lifecycle. Its repeat-same-input and second-call comparison are useful; ten-call candidate stability was pending in this snapshot. Do not describe baseline ten_layout_calls as candidate stability.
4. **Metric coverage:** strict proper crossings deliberately exclude T contacts and intersections at segment bends; pairwise shared length counts segment-pair traversal multiplicity, not geometric union length. No candidate should be selected solely by one scalar if it shifts crossings into uncounted touches. Endpoint-owner interiors are excluded from unrelated-edge penetration, and label/stroke excludes its own edge. These are declared definitions, not proof of complete route validity. Association-end labels, actual glyph ink, State multiline measured bounds and port labels are not covered by current primary label metrics. Current nine fixtures contain functional exchanges, so these omissions do not corrupt their narrow comparison.
5. **Fixture coverage:** all current fixture families are small SA FunctionalDataflow cases. Other-view exactness is vacuous where only one view exists; folding, filtering, omitted-node, State, Allocation, Scenario, undirected cycles, dense scaling, UI admission and multi-file source conservation are not established. Preserve these gaps explicitly rather than broadening the initial run unnecessarily.
## Prototype source risks the experiment should expose
The candidate preserves semantic records and route-list order, retains attachments/port anchors, rejects folded/omitted topology explicitly, and uses stable alias/ID order, deterministic cycle fallback, a graph limit and counted ordering work. Derived corners are not persisted as hard pins. No product file is replaced.
Three passes use frozen per-call minima, but those minima come from baseline Layout using the input's existing sizes; cross-call size ratcheting remains possible and should appear in repeated full-Project comparison. Global maximum label width controls every sibling gap, so one long label may balloon unrelated layout area. Incoming-neighbor ordering can improve the reversed-container fixture without proving general crossing reduction; undirected edges do not constrain ranks/order. The work budget excludes existing projection/routing work and several collections, so it bounds selected prototype loops, not total CPU complexity. With current small fixtures these are diagnostic candidate weaknesses, not reasons to prevent the run.
Interpret a failed invariant, growing repeated layout, worse collisions or huge area as evidence against this prototype. Preserve errors and unsupported statuses; do not use successful process exit as layout-quality acceptance. Decide further work from the produced geometry and independent metric vector. Production integration, complete command/source/API/history behavior, native readability and broader issue32 acceptance remain separate.
@@ -1,75 +0,0 @@
"""Render recorded probe geometry for inspection; this is not a desktop screenshot.
Usage: python render_probe.py PROBE_STDOUT_JSONL NEW_OUTPUT_DIRECTORY
Uses one scale across every result for each fixture; input geometry is unchanged.
"""
from pathlib import Path
import hashlib
import json
import sys
from PIL import Image, ImageDraw, ImageFont
def geometries(value, name=""):
if not isinstance(value, dict):
return
if "routed_edges" in value and "projected_nodes" in value:
yield name, value
return
for key, child in value.items():
yield from geometries(child, f"{name}.{key}".strip("."))
source, output = map(Path, sys.argv[1:])
output.mkdir(parents=True, exist_ok=False)
font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", 13)
files = []
for line in source.read_text(encoding="utf-8").splitlines():
item = json.loads(line)
fixture = item.get("fixture")
if not fixture:
continue
variants = list(geometries(item))
if not variants:
continue
largest_width = max(g["drawing_bounds"]["size"]["width"] for _, g in variants)
largest_height = max(g["drawing_bounds"]["size"]["height"] for _, g in variants)
scale = min(1.0, 1140 / max(1, largest_width), 690 / max(1, largest_height))
for name, geometry in variants:
canvas = Image.new("RGB", (1200, 800), "white")
draw = ImageDraw.Draw(canvas)
origin = geometry["drawing_bounds"]["position"]
def point(position):
return (30 + (position["x"] - origin["x"]) * scale,
70 + (position["y"] - origin["y"]) * scale)
def rectangle(position, size):
x, y = point(position)
return x, y, x + size["width"] * scale, y + size["height"] * scale
draw.text((20, 12), f"{fixture} / {name} | geometry only, not native UI", font=font, fill="black")
draw.text((20, 32), f"Fixed fixture scale {scale:.4f}; text below identifies bounds, not glyph measurements", font=font, fill="black")
for node in sorted(geometry["projected_nodes"], key=lambda n: (n["depth"], n["id"])):
box = rectangle(node["position"], node["size"])
draw.rectangle(box, fill="#eef2f6", outline="#687787", width=1)
draw.text((box[0] + 3, box[1] + 3), node["id"][-5:], font=font, fill="#334155")
for edge in geometry["routed_edges"]:
points = [point(p) for p in edge["points"]]
if len(points) > 1:
draw.line(points, fill="#245c88", width=2)
label = edge["label"]
if label["text"]:
box = rectangle(label["position"], label["size"])
draw.rectangle(box, outline="#ad5715", width=1)
target = output / f"{fixture}-{name.replace('.', '-')}.png"
canvas.save(target)
files.append({"name": target.name, "bytes": target.stat().st_size,
"sha256": hashlib.sha256(target.read_bytes()).hexdigest(), "scale": scale})
(output / "manifest.json").write_text(json.dumps({
"input_sha256": hashlib.sha256(source.read_bytes()).hexdigest(),
"renderer_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
"scope": "Offline schematic of recorded core geometry; no native or font-rendering acceptance.",
"images": files}, indent=2) + "\n", encoding="utf-8")
print(f"Rendered {len(files)} geometry records without modifying the probe output.")
@@ -1,66 +0,0 @@
# #32 automatic arrangement: bounded research
Prepared 2026-09-25; local research, not an accepted design or implementation review. No compiler, GUI, helper, or remote mutation was run. Primary sources were read online. Local source spot-check: clean `.local/auto-layout-20260925`, commit `715036e132677dd2bc2fb37ed316d93dc9987aec`. Parent owns current implementation mapping and contract selection.
The user needs Arrange to generate/remove bends, reduce connection intersections, and account for connection labels, while retaining meaningful nested containment/deployment. A useful solution therefore needs coordinated node ordering, space allocation, routing, and label placement. Merely sorting boxes or clearing existing waypoints cannot establish success.
## Verified precedents and their limits
**Capella workflow.** Capella 7 release notes document Layout Children, temporary movement of pinned elements, and renaming Arrange All/Selection to Layout All/Selection. This supports making operation scope and preservation of manual organization explicit. It does **not** establish that Capella uses ELK as its default engine. [Official Capella 7 notes](https://github.com/eclipse-capella/capella/wiki/Release-Notes-7.0.0).
**Sirius workflow.** Its user guide describes avoiding overlap, fitting containers around contents, attempting fewer edge crossings, and preserving pinned locations. Layout Children operates at the immediate level. A selected container can have its contents arranged while its location remains fixed. The guide also describes simplifying an unpinned edge between pinned endpoints. However, its pinning section and later toolbar section disagree about edge pinning support; do not copy that ambiguity into ARCADIA's contract. [Sirius user guide](https://eclipse.dev/sirius/doc/user/diagrams/Diagrams.html). Sirius documents configurable default/composite and ordered-tree layouts, with ELK as an additional integration described as experimental. Availability of that integration is not evidence of a particular Capella installation's behavior. [Sirius layout configuration](https://eclipse.dev/sirius/doc/specifier/diagrams/Diagrams.html).
**ELK capabilities.** ELK Layered explicitly supports orthogonal routing, ports, labels, compound graphs, and cross-hierarchy edges with suitable configuration. [Algorithm reference](https://eclipse.dev/elk/reference/algorithms/org-eclipse-elk-layered.html). `INCLUDE_CHILDREN` allows a joint run through descendants; the root default otherwise separates children. Independent child layout is therefore not equivalent to globally considering connections across nested containers. [Hierarchy handling](https://eclipse.dev/elk/reference/options/org-eclipse-elk-hierarchyHandling.html). Port constraints distinguish free placement, fixed side/order/ratio, and fixed position. [Port constraints](https://eclipse.dev/elk/reference/options/org-eclipse-elk-portConstraints.html).
The authors describe a Sugiyama-family layered algorithm, constrained barycenter crossing minimization, size/port-aware coordinate assignment, and separate support for compound graphs and disconnected components. These are heuristics with configurable priorities, not a guarantee of globally minimal crossings. [ELK authors, GD 2024](https://drops.dagstuhl.de/storage/00lipics/lipics-vol320-gd2024/LIPIcs.GD.2024.56/LIPIcs.GD.2024.56.pdf).
**Routing is a distinct problem.** Wybrow, Marriott, and Stuckey describe orthogonal visibility graphs, A* route search, and ordering/nudging of shared segments. Their bend/length optimality statement concerns individual routes under their model, not joint optimal placement of all nodes, labels, and connectors. [Orthogonal Connector Routing, GD 2009](https://people.eng.unimelb.edu.au/pstuckey/papers/gd09.pdf). libavoid exposes penalties for crossings, segments, cluster crossings and shared paths, plus endpoint direction constraints. It supplies routing rather than a complete node arrangement solution. [libavoid API](https://www.adaptagrams.org/documentation/namespaceAvoid.html).
## Materially different approaches
| Candidate | Practical proposal for this project | Main advantage | Main risk / decisive falsifier |
| --- | --- | --- | --- |
| Native Rust layered arrangement + existing router | Build a bounded, deterministic placement pipeline over the projected hierarchy; reserve measured label space and improve routes after placement. | Best match to Rust preference, existing model/history, and deployment; reuse current geometry. | Nested cross-boundary routes and label congestion make a supposedly small implementation grow. Reject if the finite compound fixtures require ad hoc per-diagram exceptions or cannot reduce known avoidable crossings. |
| ELK Layered through elkjs | Translate one immutable projected graph to ELK JSON, run a pinned bundled JS engine off the UI thread, validate results, apply a presentation transaction. | Mature joint treatment of ports, labels, layering and hierarchy. | Adds runtime/distribution/adapter cost. Reject if exact port semantics, nested coordinates, measured label boxes, bounded cancellation, or Windows/Linux packaging cannot be demonstrated. |
| Preserve nodes; improve routes and label locations | Use existing Rust routing plus bounded rerouting/order search, or investigate libavoid through FFI. | Least disruption to the user's spatial organization; useful separate Reroute command. | Cannot untangle crossings imposed by node/port ordering. Insufficient as the sole Arrange implementation if an order swap solves a fixture it cannot improve. |
elkjs is the official JavaScript form of ELK's layout algorithms, consumes/returns graph geometry, and supports worker execution. Using the distributed JavaScript does not require a Java runtime. A Rust embedding still needs an explicitly selected JS runtime or packaged process; compatibility, footprint, cancellation and licensing must be checked in a bounded spike. It is not a Rust library or a ready Iced integration. [elkjs repository and API](https://github.com/kieler/elkjs).
Graphviz is a possible comparison baseline, not my preferred default: its current official `splines=ortho` documentation explicitly says this routing does not handle ports or, for dot, edge labels. That limitation directly intersects this task. A separate router/label solver could repair the integration, but removes much of its simplicity. [Graphviz splines](https://graphviz.org/docs/attrs/splines/). Force/stress layout is another possible overview style, but I would not spend the first experiment on it: engineering flow direction, nesting and endpoint constraints still need substantial machinery afterward. This is a fit judgment, not a claim those algorithms cannot be extended.
## Proposed minimum contract, independent of engine
1. **Operate on diagram presentation.** Preserve semantic identities, relation direction, containment/deployment, port identity and connectivity, node/edge membership, and label text. Layout cycle breaking must never reverse the actual model relation. Projected parentage, not an independently guessed semantic tree, defines nesting. Hidden/collapsed content must have a declared policy; do not silently expose it.
2. **Define scope before implementation.** Initial whole-diagram Arrange is simpler than arbitrary selection. If selection is included, decide whether a container means its immediate children or its full subtree, whether it can grow, and how boundary-crossing edges update. Outside nodes remain fixed. Do not infer support for selection from a whole-graph solver.
3. **Define replaceable geometry.** Explicit Arrange may replace the in-scope route waypoints, creating useful bends and removing redundant ones. Decide independently whether authored endpoint attachments and authored label placement are preserved or reset. Recommended initial rule: preserve semantic/fixed attachments; authorize replacement of bend geometry; treat preserved label boxes as constraints. Do not retain stale absolute label offsets accidentally after wholesale rearrangement. Parent must settle this user-visible policy.
4. **Measure before arranging.** Supply visible node dimensions, headers, port/row areas, label rectangles and clearance in world units. Use the same prepared text and measurement as painting, including multiline labels and fallback glyphs. Feed label occupancy into spacing/routing, then validate the final rendered geometry. Fitting labels only after arranging boxes can recreate collisions.
5. **Atomic application.** Return a candidate presentation delta, validate it, then create one Undo entry. Failure/cancellation leaves the model unchanged. Undo restores complete prior geometry; Redo and save/reopen reproduce the result. A stale asynchronous result must not overwrite edits made since its input snapshot.
6. **Quality, not an impossible universal promise.** Require no invalid geometry, prohibited node/header penetration, or lost constraints. Minimize avoidable crossings, label collisions and shared-path ambiguity before compactness and bend count. Preserve a satisfactory baseline when candidates are worse. Hard constraints may make a zero-collision drawing impossible; report the residual rather than claiming success from a cost scalar.
The local spot-check explains one important seam: `crates/oa-core/src/session.rs::layout` already obtains `projection::parents`, recursively sizes nested nodes and rejects Scenario geometry. `routing.rs` explicitly distinguishes persisted authored pins from bounded derived routes. Generated bends need not all become persisted manual pins: persist the chosen presentation change according to a declared regeneration policy. The #36 successor's measured State labels must be reconciled when integrating; this base predates it. No claim about uninspected callers or final API follows from this spot-check.
## Native Rust candidate: finite algorithm experiment
This is a proposal, not an implementation prescription. Build a temporary layout graph with stable IDs, measured boxes, containment, real port constraints and typed edges. Determine feedback edges for cycles without modifying semantics; assign layers; insert temporary long-edge/label placeholders; perform a fixed number of alternating barycenter/median sweeps with adjacent swaps accepted only when crossing cost improves; assign non-overlapping coordinates. Lay out children with explicit boundary connection ordering and reserve parent headers/port areas. Bottom-up subtree packing alone is a baseline, not proof of cross-hierarchy quality.
Route orthogonally around the resulting obstacles, with penalties for bends, crossings and excessive shared paths. Place measured labels in reserved corridors; if conflicts remain, permit a bounded spacing/rerouting pass. Remove duplicate and collinear intermediate vertices. Keep separate metrics for edge crossings, shared-path length, label collisions, bends, area and displacement so a shorter route cannot disguise a newly unreadable diagram. Stable tie-breaking, bounded passes and retaining the best valid candidate limit oscillation and cost. Compare this candidate against the same finite fixtures processed by elkjs before investing in a general framework.
## Falsifiers and finite milestones
**First: freeze the evaluator and geometry policy.** Six small fixtures are enough to expose foundational errors: (a) a two-layer order swap with a known crossing-free solution; (b) a diamond plus cycle/self-loop; (c) a two-level OA containment graph with internal and cross-container connections; (d) SA deployment nesting with fixed semantic ports and high-degree fan-out; (e) long/multiline labels in a tight corridor; (f) disconnected components, collapsed content and an already tidy layout. Include one route needing added bends and one needing removed bends. If scope excludes any fixture feature, state that before scoring.
Count proper interior intersections between distinct routed edges separately from collinear overlaps. Exclude common endpoint contact, but do not exempt edges merely because they share a source: an intersection elsewhere still counts. Count label-label and label-unrelated-edge/node intersections; intentional own-edge label contact and container background containment need specific exemptions. Check allowed container boundary passages rather than counting every containment-border crossing as an error. Record scores on final routes, not only straight-line layer proxies.
**Second: choose using measured results.** For the known solvable fixtures, demand the known crossing/collision target, semantic equality, correct port attachment and legal containment. Test deterministic repetition, a second Arrange reaching a stable result, and small perturbations not causing unbounded growth. Include invalid inputs/work-budget exhaustion; preserve the input on failure. Set an interactive-time budget against a declared representative model size and hardware before timing, rather than inventing a universal threshold here.
**Third: verify the real workflow.** Parent performs Arrange, inspects routes and labels at normal reading zoom, Undo, Redo, save and fresh reopen on OA and SA models. Check that connections remain traceable and nesting still conveys the intended relationship; aggregate crossing counts alone do not establish readability. No such execution or acceptance is claimed by this research.
Recommended next decision: settle reset/preservation of bends, endpoint attachments and label anchors, then compare the native layered candidate and elkjs on the same compound, port-and-label fixtures. Route-only improvement is a useful fallback capability but should not silently redefine the user's Arrange request.
## Parent's current code findings: implication for the first experiment
Parent reports that the existing router already has deterministic bounded orthogonal search, obstacle exclusion, crossing/shared-run penalties and automatic label collision sampling; current Arrange uses a four-per-row root placement after topological/alias ordering. These are parent-provided inspection findings, not independent runtime verification here. They materially favor **reuse of existing routing plus improved node arrangement** as the first candidate, rather than reimplementing routing or immediately adopting another engine. Feed its final-route metrics back into a bounded choice among placement candidates; label sampling alone still cannot create missing corridor space.
Parent's proposed policy—preserve semantic ports, authored port anchors and endpoint attachment preferences; reset only visible effective bends/label overrides during explicit full Auto-layout; retain hidden/promoted metadata; leave automatic elbows derived—is a coherent candidate. Its key falsifier is visibility scope: a folded/proxy edge must not cause deletion of dormant metadata belonging to a hidden original endpoint/route. Define “visible effective” by exact original edge ID plus unsuspended geometry, not just membership in the rendered edge list. Test folded then expanded diagrams, ancestor-promoted endpoints, partially visible authored routes and a visible label whose anchor was inherited. If retained dormant metadata becomes effective on expansion, the restored manual shape is expected under this policy and should not be advertised as newly automatically arranged. Explicit full Auto-layout can reasonably reset visible label overrides because its stated purpose authorizes rearrangement, but ordinary redraw, drag and routing must not acquire that reset behavior.
Compare reuse against elkjs only after scoring this bounded candidate. A successful existing-router experiment removes much of the justification for another runtime; persistent compound/port-order failures would supply concrete reasons to reopen engine adoption. The newly observed untracked `harness/auto-layout-investigation-20260925.md` in the worktree is parent work; this research did not modify it or product source.
@@ -1,51 +0,0 @@
# #32 residual routes after terminal-join candidate J
Read-only diagnosis of run03 `command/output.log`, `.local/auto-layout-j-comparison-20260925.json`, the geometry-only crossed-bipartite PNG, and current `routing.rs` / `projection/port_layout.rs`. No edits, builds or native GUI execution. J is an experimental cost correction, not an accepted readability improvement for every scene.
## The remaining187 units are not coincident distinct ports
The four functional exchanges deliberately reuse four semantic ports:
| Flow | Source port | Target port |
| --- | --- | --- |
| 0 (`009`) | `010` | `014` |
| 1 (`00c`) | `013` | `011` |
| 2 (`00f`) | `010` | `011` |
| 3 (`012`) | `013` | `014` |
Projected source ports are `(264,106)` and `(264,286)`; target ports `(346,106)` and `(346,286)`. Each port is a single real semantic identity serving two edges. There are no authored port anchors in this fixture. The route endpoints and ports were unchanged by J. Splitting a common port into several displayed ports or changing relation port IDs would change the contract/semantics and is not a routing remedy.
Of187 pairwise shared units,72 are four legitimate common-port18-unit terminal stubs. The remaining115 are four avoidable interior overlaps:
- Flow0/Flow2: `y=106, x=282..328`, length46.
- Flow1/Flow2: `y=106, x=305..328`, length23.
- Flow1/Flow3: `y=286, x=282..305`, length23.
- Flow0/Flow1: `y=106, x=305..328`, length23. These routes have different endpoints, so this is not a common-port exemption.
These sum115. The two diagonals now have separate vertical channels (`x=328` and `x=305`); horizontal tails still merge different routes. The geometry PNG confirms that a user sees shared horizontal lines with branch contacts, not four independent readable connections. It is not native/glyph evidence.
`port_layout::layout` chooses automatic sides from peer centers, semantic fallback and clear exits; explicit anchors override the resulting side/offset. It sorts multiple automatic ports on a side by peer-axis coordinate and ID, then allocates distinct positions around fixed anchors. Here each node has only one relevant port, so improving distinct-port separation would not address this fixture. Moving a common automatic port could alter geometry but still leaves all its incident edges sharing the same physical endpoint. Fixed anchors must remain exact.
## J trades one objective against another
J improves layered diamond overlap82→36 (nonterminal0) and layered bipartite344→187 (nonterminal115). But the original unarranged bipartite regresses730→872 shared units (nonterminal658→800), while bends5→4 and length2076→2064. The current original routes use a320-unit top horizontal trunk and a160-unit second-diagonal tail; later straight edges overlap those trunks. This is consistent with a length/bend-biased objective, not evidence that J universally improves routing.
`crossing_cost` charges only0.12 per shared unit, capped80 per prior segment; a turn costs24. J now compares more complete turn costs, so it can rationally prefer a cheaper route with more overlap. The router evaluates edges in stable-ID order and does not jointly revise earlier paths. Terminal fairness alone cannot correct an objective that undervalues ambiguous shared strokes. Public/ordinary scenes must remain in the comparison; do not judge only Arrange-generated geometry.
## Next bounded experiment: penalty versus available lanes
Recommend a tiny factorial comparison with node positions, ports, anchors and edge order frozen: J; J+P; J+L; J+P+L. Keep the original unarranged bipartite as a named regression sentinel alongside layered diamond/bipartite and the existing corpus. This separates missing candidate geometry from cost preference; no placement change initially.
**P:** use one predeclared experimental overlap coefficient, e.g.3.0 instead of0.12, retaining the80 per-segment cap and proper-crossing24 initially. This is a falsifier, not a proposed final default. A12-unit dogleg around a straight shared span can cost24 additional length plus96 for four full-path turns. The cheap existing coefficient cannot compensate for that; even3.0 with the80 cap may still reject it. Record this failure explicitly rather than repeatedly tuning. A second experiment removing/changing the cap would require separate justification; the cap and segment subdivision make the objective unlike a simple global shared-length weight.
**L:** offer a bounded number of parallel candidate coordinates at `CLEARANCE=12` on either side of occupied horizontal/vertical segments, subject to current obstacle clearance and fixed terminal stubs. These are derived path candidates, never authored waypoints. Put them in fast-path candidate space and, if needed, the grid space consistently, with a deterministic global cap. The current obstacle-boundary/midpoint coordinate set does not systematically offer these close parallel lanes. More space between boxes alone cannot supply the missing candidate coordinate or change its cost preference.
A smaller staging of this comparison is to run P first and inspect actual chosen alternatives, then add L only if the recorded candidates lack the desired lane. Do not silently combine penalty, cap, edge ordering and node spacing changes. If P merely creates crossings/long exterior detours, that disproves it as a standalone improvement. If L offers legal lanes but they are never selected, that isolates the objective. The result may justify a different explicit priority or bounded shared-segment nudge, but not before this evidence.
**Alignment control:** an additional fixed24-unit inter-layer gap or stagger is lower priority. It changes the diagram and automatic peer positions, complicates attribution, and can lengthen shared trunks. Alignment may be useful for a particular placement heuristic, but it is not a direct explanation of identical horizontal tails between the same common ports. Port-placement changes are outside the identified dependency scope.
## Acceptance constraints for the experiment
Keep exact semantic graph, port identities, attachments, authored anchors and generated-versus-authored route distinction. Report raw overlap, legitimate terminal overlap, nonterminal overlap, proper crossings AND branch/bend contacts, labels, obstacles, length, turns, warnings and workload. Current proper-crossing zero excludes contacts at bends; trading coincident strokes for distinct, obvious crossings can improve traceability even if that one metric rises. Conversely, tiny offsets that appear merged at normal zoom are not success.
Use shared-port fan-out/fan-in and distinct-port controls, fixed-anchor controls, narrow corridor, authored-pin and opposite-direction routes. Compare original, reset-only and layered scenes, plus a fixed edge-ID permutation to expose priority sensitivity. Parent should inspect actual route tracing at normal zoom before adopting any weight/lanes policy. No quality acceptance or port-placement defect is asserted here.
@@ -1,106 +0,0 @@
# First automatic-layout experiment
## Decision
Retain the hierarchy/label-spacing prototype for further experiments; do not
adopt it as production Auto-layout. It improves several named fixtures beyond
resetting old bends, but regresses shared connector length in two fixtures.
Shorter routes and zero proper crossings do not establish readable connections.
The next experiment should isolate route selection at fixed node positions,
before adding more node spacing or replacing the existing routing engine.
## Method and receipt
Tested source `e7deea7039bcf31675cffbb462cfeb19d62a7e20`, based on released
`715036e132677dd2bc2fb37ed316d93dc9987aec`. No production file changed in that
commit. Windows x86_64-pc-windows-gnullvm, Rust 1.98.1, LLVM mingw, one Cargo job,
incremental compilation disabled; Linux excluded. Command:
```text
cargo run --locked --offline -p oa-core --example auto_layout_probe
```
The recorded runner completed at 2026-09-25T00:42:06Z, exit 0, unchanged inputs,
no recorded failure. stderr contains only compile/run progress. This means the
diagnostic process completed, not that layout quality passed. The JSONL has one
metadata record and nine fixture records, with full input/result Projects and
core route geometry. Its SHA256 is
`21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`.
[Evidence archive](run-01/probe-e7deea70.zip), 900995 bytes, SHA256
`c52f82d4782cd6a7f8cbe67498c8b2371e99204a65976aa8bcbbd0a86f835069`,
contains original receipts, source inventories, output, runners and 37 offline
geometry PNGs. [Manifest](run-01/manifest.json) binds every member and the
post-run executable identity. All archive members were byte-compared to the
local originals. Original absolute paths describe this machine; reproduce using
the source commit and command above, with a suitable Windows Rust toolchain.
## Observations
Values below compare existing Layout with the layered prototype. Reset-only
matches existing Layout except for the authored-detour fixture, where it already
reduces length to 240, bends to zero and area to 90816. Shared length is pairwise
segment overlap, not the union of occupied space; area uses recorded bounds.
| Fixture | Shared length | Label/node collisions | Route length | Bends | Area |
| --- | ---: | ---: | ---: | ---: | ---: |
| Four-node chain | 0 → 0 | 0 → 0 | 720 → 246 | 0 → 0 | 213312 → 150744 |
| Seven-node chain | 0 → 0 | 0 → 0 | 2560 → 492 | 8 → 0 | 523584 → 271920 |
| Diamond | 36 → 82 | 0 → 0 | 2200 → 688 | 8 → 4 | 300576 → 260832 |
| Crossed bipartite | 276 → 344 | 0 → 0 | 3284 → 688 | 12 → 4 | 300576 → 165360 |
| Nested cross-boundary | 0 → 0 | 1 → 0 | 1076 → 364 | 6 → 2 | 284096 → 366528 |
| Authored detour/label | 0 → 0 | 0 → 0 | 2348 → 187 | 6 → 0 | 628040 → 83820 |
| Fixed ports | 0 → 0 | 0 → 0 | 916 → 863 | 4 → 4 | 125976 → 116754 |
| Reversed children in two containers | 148 → 0 | 1 → 0 | 872 → 372 | 4 → 0 | 288512 → 272800 |
| Long ordinary labels | 36 → 36 | 2 → 0 | 1340 → 1436 | 4 → 4 | 200448 → 208800 |
Proper interior crossings, unrelated node overlaps, unrelated edge/node
penetrations, label/label collisions, unrelated label/stroke intersections and
route warnings are zero in the baseline, reset and candidate outputs. This is
not proof of crossing elimination: the crossing definition excludes bend and
T contacts, and overlapping strokes can make endpoint pairing ambiguous.
The parent inspected offline geometry for the reversed-container baseline and
candidate, crossed-bipartite candidate and long-label candidate. Reordering the
right container's children separates the two routes; the bipartite result has
a visually ambiguous shared central trunk. The long-label boxes occupy the
available corridors. These images render core boxes/lines, not actual label
glyphs or the desktop application, and therefore are not native UI acceptance.
Every candidate reports exact same-input determinism, idempotence and equality
to its first result for calls 2–10. Reported semantic, node identity/metadata and
nongeometry conservation hold. JSON and canonical single-source parse/format
round trips hold for all nine before/baseline/reset/candidate Projects. The
authored-detour route changes intentionally. These assertions do not separately
establish hidden-route or attachment lifecycle policy. Other-view conservation
is vacuous in these single-view fixtures.
Existing Layout's Session operation passes one-step Undo/Redo and history
checks. The pure candidate function has no integrated command/history evidence.
The [source review](probe-review.md) defines remaining metric and fixture gaps.
Folded/filtered topology, State/Allocation diagrams, cycles/undirected graphs,
large models, multifile sources, application/API admission and native editing
remain outside this run. Issue36's multiline State candidate is not in this base.
An [independent results audit](results-audit-01.md) checked receipt bindings,
complete Projects, all 37 image hashes and eight offline images. It independently
recomputed both shared-route regressions and confirmed the scoped conclusions.
## Implications
Resetting obsolete bends is useful but insufficient. Hierarchy ordering and
label clearance have distinct value, with measurable area/length tradeoffs.
Increasing a global gap cannot be assumed to fix shared-route ambiguity.
Inspect the existing router's candidate scoring and compare complete endpoint
join costs, overlap penalties and available lane candidates using the same
geometry. Preserve the full quality vector and endpoint/obstacle invariants;
reject a change that merely converts overlap into uncounted contacts.
The [routing inspection](routing-experiment-plan.md) identified a concrete
asymmetry: a locally selected route leg scores the source join but omits the
target-stub join until after choosing that leg. Test that small correction first,
at unchanged node positions, before the auditor's proposed alignment/spacing
alternatives. This is a falsifiable source-based hypothesis, not a conclusion
that it explains all shared routes. A separate committed candidate will preserve
this first control; no overlap weight or node placement should change in that
comparison.
@@ -1,56 +0,0 @@
# #32 first experiment — independent results audit
Source e7deea7039bcf31675cffbb462cfeb19d62a7e20, production baseline715036e132677dd2bc2fb37ed316d93dc9987aec. Command: `cargo run --locked --offline -p oa-core --example auto_layout_probe`; Windows x86_64-pc-windows-gnullvm/dev. Recorded exit0, failure=null, source inputs unchanged. Independently checked receipt-bound log hashes and equal before/after source inventories. No rerun, compiler, GUI or model helper executed.
**Conclusion: useful evidence for continued experimentation, not a production winner.** All nine finite fixtures completed; candidate conservation/repeat/roundtrip checks pass. Two shared-run regressions are real, while nested/reversed-container/long-label improvements are also supported. There are no predefined quality thresholds, so exit0 means the probe ran, not that layout quality passed.
## Verified results
Exactly one metadata row plus nine fixture rows. Every candidate is supported and valid as recorded, repeats exactly from identical input, equals its second-call result, and remains equal to its first result through calls2–10. Existing Layout likewise has passing repeat/history checks. Every before/after/reset/candidate canonical JSON and single-source roundtrip is recorded exact. Candidate semantic/node-identity/visibility/port-anchor/nongeometry booleans are true on all nine. I independently compared complete output Projects after restoring only diagrams, and checked target layout fields and route attachment fields against input: no difference. Most attachment lists are empty, so this is not broad attachment coverage. Other-view checks are vacuous for single-view fixtures.
The authored_detour_and_label candidate intentionally has authored_routes_exact=false because its three pins and label override are removed. That is the experimental reset policy, not an unexplained conservation failure. Reset-only already removes the detour; layered must earn its additional complexity elsewhere. Actual Undo/Redo was executed only for existing Command::Layout. Layered is a pure transformer with no command/UI integration or history evidence.
Values below compare **baseline Layout plus reset-only control → layered candidate**, not the original hand-placed input:
| Fixture | Shared length | Label/node pairs | Bends | Route length | Drawing area |
| --- | --- | --- | --- | --- | --- |
| flat_chain_4 | 0 → 0 | 0 → 0 | 0 → 0 | 720 → 246 | 213312 → 150744 |
| chain_7_row_wrap | 0 → 0 | 0 → 0 | 8 → 0 | 2560 → 492 | 523584 → 271920 |
| diamond | 36 → 82 | 0 → 0 | 8 → 4 | 2200 → 688 | 300576 → 260832 |
| crossed_bipartite | 276 → 344 | 0 → 0 | 12 → 4 | 3284 → 688 | 300576 → 165360 |
| nested_cross_boundary | 0 → 0 | 1 → 0 | 6 → 2 | 1076 → 364 | 284096 → 366528 |
| authored_detour_and_label | 0 → 0 | 0 → 0 | 0 → 0 | 240 → 187 | 90816 → 83820 |
| fixed_ports | 0 → 0 | 0 → 0 | 4 → 4 | 916 → 863 | 125976 → 116754 |
| two_containers_reversed_children | 148 → 0 | 1 → 0 | 4 → 0 | 872 → 372 | 288512 → 272800 |
| long_ordinary_labels | 36 → 36 | 2 → 0 | 4 → 4 | 1340 → 1436 | 200448 → 208800 |
All these control/candidate outputs report zero strict proper crossings, unrelated-node collisions, unrelated edge/node penetrations, label/label pairs, unrelated label/stroke pairs and routing warnings. Therefore this run provides **no discriminating evidence of proper-crossing reduction**. Zero warnings is not proof of unambiguous independent routes.
## Independently checked regressions and improvements
- **diamond:** shared length36→82. Control has two18-unit common terminal runs. Candidate retains those and adds one46-unit horizontal shared run for edge pair0009/000c. Nonterminal shared length0→46; this is not just a terminal-exemption artifact. Bends8→4 and length2200→688 improve, but they partially come with merged routing.
- **crossed_bipartite:** shared276→344, nonterminal204→272. Control has four18-unit common-tip runs plus204 horizontal. Candidate has those same72 terminal units, two additional46 horizontal overlaps, and a180-unit vertical overlap between distinct edge pairs0009/000c. Independent axis-interval sums match the emitted values exactly. A more compact drawing and fewer turns do not erase this distinguishability regression.
- **nested_cross_boundary:** reported label/node collision1→0 and route length1076→364; area284096→366528 increases about29%. The geometry PNG shows the parent widened to place its children horizontally. This is a real tradeoff, not universal improvement.
- **two_containers_reversed_children:** shared148→0, label/node1→0, bends4→0, length872→372 and area288512→272800. The hand-authored alternate child order exists independently; the candidate's straight separated connections support a meaningful ordering improvement over reset-only.
- **long_ordinary_labels:** label/node2→0, shared36 unchanged, but length1340→1436 and area200448→208800 grow. This is supported clearance-for-space tradeoff using approximate core rectangles, not native glyph evidence.
Viewed eight offline PNGs: baseline/candidate diamond, baseline/candidate crossed_bipartite, baseline/candidate nested_cross_boundary, candidate two_containers_reversed_children and candidate long_ordinary_labels. They corroborate route sharing and spacing changes. All37 image identities and their manifest binding to the original output log were checked. Images are schematic rectangles/polylines with fixed scale per fixture, not application renders or text measurements.
## Method limits versus actual failures
Proper-crossing definition excludes T contacts and bend intersections; shared length counts pairwise traversal multiplicity. I recomputed the two reported regressions independently from axis-aligned intervals, so those particular increases are actual geometry outcomes, not metric bugs. An unconditional dominance claim fails on those results, but the experiment has not predeclared a total preference ordering across compactness and sharing. Retain the whole metric vector.
Reset eligibility is post-baseline-Layout versus pre-layout in the candidate; equivalent for current unchanged-visibility fixtures only. No folded/filter/omitted-node/State/Allocation/undirected-cycle/dense scaling/UI admission/multi-file source lifecycle acceptance follows. The source work budget is partial and runtime complexity was not established here. No native GUI, universal label-ink correctness, candidate command Undo, or issue32 completion is claimed. Base715 lacks the separate36 measured State label follow-up.
## Next falsifiable experiment
Keep these nine frozen inputs and add one explicit orthogonal proper-crossing witness plus a non-incident overlap/touch counterexample to verify the evaluator distinguishes them. Then isolate diamond/bipartite routing interaction with a tiny predeclared set of node-placement alternatives (current top alignment, centered rank, deterministic stagger, conservative wider gap), keeping the router unchanged. Record actual routed metrics for every alternative; do not silently choose whichever plot looks best or optimize only bend count.
Hypothesis: a bounded alignment/spacing change can remove the candidate's excess nonterminal sharing without surrendering reversed-container and long-label gains. Falsifier: no alternative reaches control-or-better shared length while retaining no new obstacle/label collisions and predeclared reasonable area/length bounds. Use controls' reported geometry as a fixed comparator and preserve every alternative; if it fails, investigate router channel/parallel-edge handling rather than repeatedly widening all spacing or introducing a whole external engine. This next probe remains diagnostic; attachment/hidden-route sentinels and real command/history/native validation follow before production selection.
Evidence SHA256:
- 01-probe/command/result.json: `119179803e8c26b960ca4280e0429bb537a6f9ff5666267e49bfab989f48dc73`
- 01-probe/command/output.log: `21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`
- 01-probe/command/inputs-before.json: `2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe`
- 01-probe/command/inputs-after.json: `2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe`
- geometry/manifest.json: `022fa0f307f9fb92fccbbc139637c62f40d1dcc3a4ea555a35c6b08d82bdb3b5`
@@ -1,92 +0,0 @@
# Target-join scoring experiment
**Keep experimental.** Accounting for the target turn during route-leg selection
confirms the suspected source/target scoring asymmetry, but does not establish
uniform readability improvement. The original bipartite scene becomes more
overlapped. Do not integrate this branch as a completed Arrange fix.
Production routing/test source is `497c1ad8b39788148c5f03bc8542d6d8e28dbc01`.
Successor `08656b18bf8934cf264469cf68fc6dea97c15cbb` only resolves three strict
Clippy findings in the diagnostic observer. Probe runs at both commits emitted
the same 371192 bytes, SHA256
`f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
The [independent source review](terminal-join-source-review.md) and
[independent results audit](terminal-join-results-audit.md) retain the scoped
claims and limitations. The latter predates the completed contact audit below.
The [evidence archive](run-j/terminal-join-08656b18.zip) contains original runs
02–06, including the failed Clippy run, source inventories, full Projects and
geometry, comparison JSON, independent contact audit/script, runners and 37
offline geometry images. It is 3178939 bytes, SHA256
`bd2146237353af05b8667dc7bd728007143a2f1b24ad9f8728fdbc50ffb3368e`.
[Manifest](run-j/manifest.json) records every member; every archived byte was
compared with its original. Paths in original receipts identify the builder's
machine, not a dependency on a peer's filesystem.
## Checks and comparison
Windows Rust 1.98.1 gnullvm, locked/offline, one job, incremental disabled;
Linux excluded. All receipts close with unchanged inputs and no runner failure.
```text
cargo test --locked --offline -p oa-core --lib --test release_routing --test routing_geometry --test routing_labels --test state_diagrams --test group_movement
cargo run --locked --offline -p oa-core --example auto_layout_probe
cargo clippy --locked --offline -p oa-core --all-targets -- -D warnings
```
Tests: 185 passed, zero failed/ignored (132 library, 7 group movement, 13 release
routing, 18 routing geometry, 2 routing labels, 13 State). Three new private tests
exercise fast/grid terminal scoring in four orientations, absent continuation,
straight/reversal and zero-length legs. Existing authored-pin/attachment/history
checks pass. Initial Clippy rejected two manual-range expressions and one nested
if in the observer; after that observer-only cleanup, strict core/all-target
Clippy passes and the rerun output is byte-identical. No whole-workspace/native
acceptance is implied.
Across all 37 before/baseline/reset/layered/manual-witness variants, complete
Projects, projected nodes, projected ports and exact route endpoints are
unchanged versus the first experiment. This isolates routing/label placement;
it is stronger than merely reusing fixture input. All nine candidate invariants,
round trips, deterministic repeats and calls 2–10 remain exact. The candidate
still has no integrated command Undo/Redo evidence.
- Layered diamond: shared length 82→36, nonterminal 46→0; all other original
metrics unchanged. Remaining 36 units are common terminal stubs.
- Layered bipartite: shared length 344→187, nonterminal 272→115; routed drawing
area 165360→175960. Labels, bends, length and other recorded metrics unchanged.
Seven other layered metric vectors are unchanged.
- **Original bipartite regression:** sharing 730→872, nonterminal 658→800;
bends 5→4 and length 2076→2064. The scoring change can favor fewer bends over
distinguishable routes. This is not a monotonic quality improvement.
- Original diamond sharing 136→36; original two-container sharing 200→54;
existing Layout/reset-only two-container sharing 148→18. The independent
audit lists the complete changed vector; 30 of 37 variants are unchanged.
The separate Python contact audit uses orthogonal interval reasoning to
reconstruct BOTH old and new contacts. Primitive witnesses pass; all 37 new
contact/proper counts match Rust, and all 37 old proper counts match v1. Layered
diamond contacts decrease 3→2. Layered bipartite contacts increase 8→9: eight bend
contacts become six bend plus three T contacts. Proper crossings remain zero.
Thus decreased coincident length partly trades into branch contacts. Details,
edge IDs, coordinates and definitions are in the archive's
`support/auto-layout-contact-audit-result-20260925.json`; script is adjacent.
There is no inferred aggregate quality pass.
The parent viewed diamond/bipartite offline images: diamond branches separate,
but bipartite horizontal tails remain visually joined despite separate vertical
channels. These are schematics of core bounds, not native application or glyph
evidence. The [residual diagnosis](residual-routing.md) confirms four genuine
shared semantic ports; distinct-port placement is not the defect. Of 187 shared
units, 72 are bounded common-port stubs and 115 are avoidable interior overlap.
## Next discriminating comparison
Retain this J result as a frozen control. Test one predeclared overlap coefficient
3.0 instead of 0.12, with the existing per-segment cap 80, crossing cost 24,
node/port geometry and edge ordering unchanged. This P variant is an isolated
experiment, not a proposed default or a release-ready source change. Preserve
the original bipartite regression as a sentinel and the entire quality vector.
If stronger penalties cannot choose useful existing alternatives, inspect
bounded parallel lane candidates separately; do not silently combine scoring,
spacing, caps and ordering changes. A candidate that shifts overlap into hard-to-
follow contacts, label collisions or large detours has not solved the user task.
@@ -1,112 +0,0 @@
# Complete scoring/lane comparison
**Stop tuning these nine fixtures; retain the variants as experimental evidence.**
Bounded parallel lane candidates have some measurable value, but do not resolve
the compact bipartite ambiguity and introduce a routing-cost concern. The
stronger overlap coefficient is no longer present at the branch tip. No routing
or Arrange replacement has been accepted for production.
PL source `d0be9ff0674373fcf9623daf62bbf50dad02c4df` combines target-join J,
coefficient 3.0/cap 80 and bounded lanes. L source
`e8ec6dbb3160f62476a5557f14605f68959f65fe` restores coefficient 0.12, retaining
J and lanes. Each leg keeps every obstacle coordinate and adds at most 64
deterministic coordinates per axis at CLEARANCE offsets from settled other-edge
segments. Fast/grid searches receive the same augmented space. Endpoint geometry,
authored pins, attachments and model metadata are not edited by this operation.
The [source review](lanes-source-review.md) records attribution limits: retained
coordinates are bounded, but collection/sorting of prior segments is not charged
to the search budget. Extra axes can hit the existing grid-cell cap and can alter
grid scores through segment subdivision. This is not a proof of globally optimal
paths or constant preparation cost. No new engine/runtime dependency was added.
## Results
Every one of the 37 complete Projects, node sets, port sets and exact endpoints
matches its control in both comparisons. All nine candidate invariants,
roundtrips and repeated-call checks hold. Values below are raw pairwise shared
length for the crossed-bipartite fixture; complete vectors remain in the archive.
| Router | Original scene | Existing Layout/reset | Layered candidate |
| --- | ---: | ---: | ---: |
| Released router | 730 | 276 | 344 |
| J | 872 | 276 | 187 |
| J + stronger penalty (P) | 730 | 276 | 187 |
| J + stronger penalty + lanes (PL) | 724 | 72 | 176 |
| J + lanes, original penalty (L) | 724 | 276 | 176 |
PL's existing-Layout/reset result eliminates 204 nonterminal shared units but
adds one proper crossing, 24 route-length units and 19392 area units. Contacts
decrease 6→5; these tradeoffs stay explicit. L with the original coefficient
does not achieve that baseline improvement. Both lane variants leave 104
nonterminal units in the compact layered case, with nine point contacts. Its
drawing area returns from J's 175960 to 165360. Eight other layered metric
vectors are unchanged. The parent viewed the PL bipartite schematic: vertical
channels are separated, but horizontal tails still join at ambiguous branches.
Compared with J, L reduces original bipartite sharing 872→724 and original
two-container sharing 54→12 without changing the other original quality fields;
two-container baseline/reset sharing reduces 18→12. PL compared with P includes
a two-container original sharing regression 6→12 while reducing one bend, 12
length units and one contact. The [PL audit](penalty-lanes-audit.md) documents all
seven changed rows; no scalar is treated as a universal quality score. Labels,
obstacles and warnings remain separately checked. Core schematics and approximate
label boxes do not establish actual glyph layout or native route traceability.
## Verification and evidence
Same frozen Windows Rust1.98.1 gnullvm environment, one Cargo job, locked/offline,
incremental disabled. Linux excluded. All runs close with exit0, unchanged
inputs and no runner failure:
```text
# PL: five matched tests, including all three new lane tests
cargo test --locked --offline -p oa-core --lib lane
# L: 188 tests passed, zero failed/ignored
cargo test --locked --offline -p oa-core --lib --test release_routing --test routing_geometry --test routing_labels --test state_diagrams --test group_movement
# Both variants: complete nine-fixture diagnostic
cargo run --locked --offline -p oa-core --example auto_layout_probe
# L: strict core/all-target Clippy passed
cargo clippy --locked --offline -p oa-core --all-targets -- -D warnings
```
The full 188 check is for L, not PL: an existing private J test intentionally
asserts the original 0.12 cost. PL's filtered run executes three new lane tests
and two existing Scenario tests matched by `lane`; 130 other library tests are
filtered. Lane witnesses cover base-coordinate preservation, 64-extra bounds,
deduplication/order independence, relevance ranking, nonfinite rejection and
fast/grid selection of a feasible parallel path under the experimental cost.
**Cost signal:** routing_geometry's 18-test runtime is 16.43s under L versus
4.30s under J on the same machine/environment. This excludes compilation, but
is one suite observation per variant, not an isolated route benchmark or a
performance bound. It warrants profiling before adopting per-leg lane scans.
Whole cargo/probe elapsed times include compilation and are unsuitable for that
comparison.
The [independent final L/four-way audit](lanes-results-audit.md) confirms all 37
fixed bindings and the 188-test result, checks the recorded geometry/contact
evidence, and likewise recommends withholding L from production pending the
independent corpus and route-only timing.
[Evidence archive](run-lanes/lanes-e8ec6db.zip), 3518507 bytes, SHA256
`5512b4cbd99e3bf03eb975e25fb980f7b1a95a5cb19f3687fb3d6d83d1839e8f`,
contains original runs08–12, 74 offline images, complete comparisons, independent
axis-based contact audits, binary identities and runners. [Manifest](
run-lanes/manifest.json) binds every member, all byte-compared to originals.
PL output SHA256 `04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd`;
L output SHA256 `64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d`.
The earlier P result and original archive remain linked in [results-p.md](results-p.md).
## Decision and next evidence
Do not choose a global router policy from these nine scenes. Freeze a small
independent corpus before the next run: realistic authored nested/folded content,
mixed-direction shared/distinct-port fan-in/out with a fixed edge-ID permutation,
and a modest sparse diagram for isolated routing-time/budget observations. Compare
J and L with an explicit route-tracing rubric and full quality vector. Preserve
the original Scene/Arrange distinction and source/history lifecycle constraints.
This should decide whether the lane cost is justified or the simpler router
should be retained before broadening the Layout prototype. Fold/filter rules,
one-command Undo, API/source parity and real desktop acceptance remain required;
the separately pending State-label issue36 is not silently included here.
@@ -1,50 +0,0 @@
# Capped overlap-penalty experiment
**P alone does not solve the arranged bipartite overlap.** Source
`3d7adff923dee5bed54dfdccc119dbee0c7c2773` changes only the overlap coefficient
from 0.12 to 3.0 (plus an experiment comment), retaining the per-segment cap 80.
Node placement, ports, target-join J logic, edge order and crossing cost remain
unchanged. This is a transient diagnostic source variant, not a proposed default.
Windows command `cargo run --locked --offline -p oa-core --example
auto_layout_probe` completed exit 0 with unchanged inputs at
2026-09-25T01:04:57Z. Same frozen Rust1.98.1 gnullvm environment as J; Linux
excluded. Output SHA256
`13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
J's 185 passing tests and strict Clippy are not claimed for P; this run executes
the diagnostic observer and its analytic primitives only.
[Original evidence archive](run-p/penalty-3d7adff.zip), 916568 bytes, SHA256
`6b819b01c8012aa72d423443f4dc04ae261f1ee9dc6907f0063c219ff173ad36`,
contains receipts, complete Projects/geometry, independent contact audit,
comparison, renderer output and runner. [Manifest](run-p/manifest.json) binds
original bytes and post-run probe executable; every member was checked against
its local original.
Complete Projects, nodes, ports and route endpoints are exact versus J in all
37 variants. All nine layered candidates retain the previous quality vector;
in particular bipartite sharing remains 187 (115 nonterminal), with nine contacts
and zero proper crossings. Two original-scene vectors change; the other 35 do
not:
| Original scene | Shared length J → P | Bends | Route length | Point contacts |
| --- | ---: | ---: | ---: | ---: |
| Crossed bipartite | 872 → 730 | 4 → 5 | 2064 → 2076 | 9 → 10 |
| Reversed children in two containers | 54 → 6 | 4 → 5 | 1512 → 1524 | 2 → 3 |
The bipartite result restores the first experiment's original-scene vector;
the extra bend/length tradeoff was predicted by the low overlap cost diagnosis.
Both contact increases remain visible rather than being counted as a clean
readability win. These results concern core geometry, not native route tracing.
The [independent P audit](penalty-results-audit.md) confirms these results and
all nine recorded conservation/roundtrip/repetition checks. Both additional
point contacts are T contacts; no proper crossing change is hidden by the table.
The next L comparison adds a bounded number of deterministic parallel lane
coordinates while preserving all existing obstacle coordinates and fixed
endpoints. Use the same augmented geometry for fast/grid search. P+L and J+L
will distinguish available alternatives from preference. The cap 80 may still
reject a four-turn detour whose extra length/turn cost exceeds it; retain that
outcome rather than retuning cap, ordering and spacing together. No weight or
lane policy is accepted for production by this diagnostic run.
@@ -1,53 +0,0 @@
# #32 next routing experiment: distinguish shared terminals from ambiguous trunks
Local source/receipt diagnosis only; no builds, formatters, GUI or product edits. Input: completed `e7deea70` probe `.local/auto-layout-checks-20260925/01-probe/command/output.log`; implementation read from `.local/auto-layout-20260925/crates/oa-core/src/routing.rs`. The probe uses **core estimated label bounds**, not renderer glyph measurement. No new candidate module is justified until the required private routing hook is agreed.
## Exact observed geometry
The layered diamond has 82 units of pairwise shared length: 36 classified as common terminal stubs, 46 nonterminal. Edges ending `009` and `00c` share the physical output `(264,106)`, its 18-unit stub to `(282,106)`, then an avoidable extra horizontal run to `(328,106)`. Edge `00c` then turns down to `(328,286)` and enters `(346,286)`. A candidate branching immediately at `(282,106)`, going to `(282,286)`, then right to the target would separate that extra 46-unit trunk while preserving the port and stub. This is a geometric proposal, not a verified collision-free final result; the same obstacle and label checks must evaluate it.
The layered crossed-bipartite case has 344 shared units: 72 common-terminal, 272 nonterminal. Its opposite diagonal routes both use `x=328, y=106..286`, an exact 180-unit coincident vertical run. Top and bottom horizontal portions add 92 nonterminal shared units. The source stubs are at `x=282`; target stubs at `x=328`. Proper crossings are reported as zero, but these coincident routes do not provide unambiguous independent traces. Do not treat the zero as a solved crossing problem.
## Source evidence: a local scoring asymmetry precedes penalty tuning
`crossing_cost` charges `min(shared_length * 0.12, 80)` per previously occupied segment, multiplied by segment count. A proper interior crossing costs24. `BEND_COST` is24. `RoutingSpace::new` uses obstacle boundary coordinates; fast-path candidates add the start/end midpoint, and grid coordinates add start/end. Neither systematically adds lanes offset from previously occupied trunks.
More importantly, `fast_path(start, end, space, previous, incoming)` includes the turn from the preceding source-side segment, but has no outgoing direction parameter. `route_edge` chooses this local path and only later appends the final target attachment point `b.point`; complete `path_cost` is then compared across endpoint choices, not across the discarded alternative paths for that same endpoint pair. With fixed semantic ports there may be no alternate endpoint choice to recover the discarded route. `grid_path` is only a fallback when `fast_path` returns None, not a better-cost search after a valid fast path.
For the diamond, horizontal-then-vertical has one internal bend and no incoming bend; its 46-unit shared portion costs5.52. Vertical-then-horizontal has one internal bend plus an incoming bend, costing24 extra locally. But appending the target segment adds the missing final bend to horizontal-then-vertical. Complete paths have equal bend counts; the local comparison prefers the shared route because it omitted one terminal join. The 180-unit bipartite overlap costs21.6, also below one turn. This explains a plausible bias, not proof that correcting it resolves every route.
## Minimal discriminating comparison (proposal to parent)
Freeze layered node positions, labels' text, attachments, port identities/anchors, edge order and work budgets. Compare a small fixed sequence, not an open parameter search:
1. **J: symmetric terminal-join cost.** Supply an optional outgoing point/direction to fast-path scoring. For the final segment to `b.stub`, use `b.point`; include `turn_cost(penultimate, end, outgoing)` both in actual candidate score and admissible pruning estimates where applicable. Intermediate authored pins have no predetermined outgoing direction; do not invent one. If grid routing supports this experiment too, target state selection must account for the terminal turn before returning the best result. Preserve baseline behavior for absent outgoing context. This isolates the suspected bias without stronger penalties or enlarged diagrams.
2. **JP: J plus stronger shared-run penalty.** One declared test coefficient, e.g.1.0 per unit with the existing80 cap, compared with0.12. Keep the proper crossing cost24 unchanged so the comparison exposes whether penalizing overlap merely substitutes crossings. Do not choose this variant solely by shared length. Preserve all hard endpoint constraints.
3. **JPL: JP plus bounded lane candidates.** For occupied horizontal/vertical trunks, offer parallel offsets of `CLEARANCE` on either side where applicable; validate obstacle clearance and fixed terminal stubs. Use a strict deterministic global cap on added coordinates/candidates and reuse existing work exhaustion handling. This tests whether absent geometric alternatives, rather than insufficient penalty, is the blocker. No persisted waypoint authoring and no unconstrained port movement.
4. **Spacing control.** Only if J/JP fail, compare the unchanged router with one fixed additional inter-layer gap (e.g.24 world units). This is a control, not the assumed remedy: larger gaps may lengthen shared trunks and enlarge diagrams while retaining identical topological ambiguity. Do not mix spacing and router changes in the first comparison.
The first J variant is the smallest informative next experiment. If it removes diamond's extra trunk while retaining invariants, stop and inspect results before implementing JP/JPL. A clean shared terminal fan-out need not eliminate its unavoidable initial18-unit stub. Conversely, sharing a node identity does not exempt arbitrary later overlap, and different physical ports on the same node must not be collapsed into one endpoint exemption.
## Required hook and ownership boundary
The candidate module can call public `route_diagram`, but cannot change private `crossing_cost`, `fast_path`, `grid_path` or candidate generation. Returning a changed Project with temporary authored waypoints would test a different policy and would violate the generated-elbows-remain-derived experiment. Copying the entire router into an example introduces unnecessary divergence.
Therefore propose a parent-owned isolated routing experiment hook, with no default production behavior change, or a separate disposable source variant controlled by the existing runner. Evaluator needs an optional routing provider returning `RoutedView` for a fixed Project, rather than only `candidate -> Project`. It must reuse that provider for every metric, capture, and repeat check and label the variant explicitly. Until parent approves that hook, no module/interface changes were made. The current original/reset/layered comparisons remain reproducible.
## Falsifiers and risks
Evaluate both raw and terminal-excluded shared length, proper crossings, T/bend contacts, route lengths/turns, unrelated-node/header penetration, label collisions, warnings and runtime/work counts. A positive overlap moved onto a bend is not a successful reduction in intersections. The crossed K2,2 fixture with fixed port ordering may require a genuine visible crossing or an outer detour; do not demand zero overlap AND zero crossings without a fixed-attachment feasible witness. Separate forced terminal contacts from independently traceable route interiors.
Keep diamond, crossed-bipartite, chain and long-label fixtures; add a fixed shared-output fan-out, two distinct ports on one node, opposite-direction connections, and a narrow obstacle corridor. Verify exact endpoint coordinates and metadata; preserve ordinary authored pins and preview/settled agreement if the routing change advances beyond this isolated experiment. Stable-ID order can privilege earlier routes, so rerun the same graph under a fixed edge-ID permutation and disclose sensitivity instead of relabeling edges to improve the score.
Labels are placed after paths settle; lane changes can worsen label collisions even when node positions stay fixed. Parent's eventual GUI inspection should trace each diagonal from its source label/port through the corridor to its intended target at normal zoom. No geometry metric alone establishes that user outcome. This note selects a falsifiable experiment, not an accepted product fix.
## Exact J patch plan, held for parent's separate candidate pin
No edits to `routing.rs` are authorized yet. After parent publishes the first experiment evidence, the narrowly proposed change is:
- Add `outgoing: Option<Position>` beside `incoming` in private `fast_path` and `grid_path` only. At `route_edge`'s loop over authored pins followed by `b.stub`, pass `Some(b.point)` only when `index == pins.len()`; pass `None` for every intermediate waypoint. The preceding settled path still supplies `incoming` exactly as now. No public API or metadata change.
- In `fast_path`, extend its shared `join(path)` closure with the terminal turn from `path[path.len()-2]` through `end` to `outgoing`, when two path points exist. Both `estimate(path)` and actual scoring already call `join`; change both consistently through that closure. Keep the two-bend lower-bound early exit: Manhattan distance plus two bend costs remains a lower bound for two-bend alternatives because terminal penalties are nonnegative. Keep final whole-path `path_cost` unchanged; local scoring does not persist a cost, so it does not double-charge the returned path.
- In `grid_path`, add the terminal turn **during relaxation when `next == last`**, using `turn_cost(a, b, outgoing)`. Include it in `costs[state]` and the queue priority before the target state can be popped. Do not merely add a penalty after returning the first reached target: that would fail to compare alternative arrival directions. The existing Manhattan heuristic remains admissible because the new terminal penalty is nonnegative. The initial incoming-turn logic remains unchanged.
- `start == end` has no locally selectable segment. Keep the degenerate result, and rely on whole-path scoring for the junction between preceding/following points. Do not fabricate a direction from an absent penultimate point. Waypoint positions/order remain exact; this patch does not claim globally optimal look-ahead across several hard-pin legs.
Focused tests before comparing full fixtures: (1) fast-path diamond geometry with one occupied horizontal trunk, fixed start/target stubs, asserting the equal-complete-bend alternative branches earlier; (2) directly exercise grid routing with two clear arrivals where adding the target join changes the preferred total, compare complete cost to an enumerated feasible alternative; (3) mirrored/rotated terminal geometry, including straight continuation and reversal costs; (4) outgoing=None preserves established intermediate-waypoint behavior; (5) full route with one/multiple authored pins retains exact pins and terminal attachments, plus start=end leg; (6) preview versus settled geometry remains consistent under the same baseline/budget. Use private unit tests for fast/grid so a passing public route cannot accidentally avoid the grid test. Then rerun the unchanged probe corpus and report the complete quality vector, especially any newly visible crossings. No expected overall improvement is asserted before execution.
@@ -1 +0,0 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -1,217 +0,0 @@
{
"source_commit": "e7deea7039bcf31675cffbb462cfeb19d62a7e20",
"baseline_commit": "715036e132677dd2bc2fb37ed316d93dc9987aec",
"scope": "Nine small SA FunctionalDataflow diagnostic fixtures; Windows core geometry, not native UI or production acceptance.",
"binary_after_completed_run": {
"path": "target/debug/examples/auto_layout_probe.exe",
"bytes": 24039424,
"sha256": "a95736170f58d25c60a16f2683b961aad8b31f97e4357c3e0d2f7e81d21176bd"
},
"members": {
"run/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"run/command/context.json": {
"bytes": 3488,
"sha256": "4dd4e602c2b33fd229a7241e1a4d6a2de399df197b5613af4b3126bfd357c476"
},
"run/command/inputs-after.json": {
"bytes": 1722092,
"sha256": "2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe"
},
"run/command/inputs-before.json": {
"bytes": 1722092,
"sha256": "2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe"
},
"run/command/output.log": {
"bytes": 331975,
"sha256": "21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1"
},
"run/command/result.json": {
"bytes": 4124,
"sha256": "119179803e8c26b960ca4280e0429bb537a6f9ff5666267e49bfab989f48dc73"
},
"run/command/stderr.log": {
"bytes": 279,
"sha256": "492e4346b5daf9d9eed2aa96c89c5104b9d8d7f830074b1346c9f5aaf053d662"
},
"run/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"run/orchestration.log": {
"bytes": 165,
"sha256": "e4bf56f792c8e8fc9288fc08ef5f0159941b8026e435a427722b59ccc4e34831"
},
"geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"geometry/crossed_bipartite-before.png": {
"bytes": 13413,
"sha256": "8622726dfdfc01e93fcd2d9d22c6d082e5a169b9dcd59f788e876954431214fd"
},
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13848,
"sha256": "de238d7e904a050b93cc63926f9b4b4723d4b98e6741971fc98f81d771a8a52e"
},
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"geometry/diamond-before.png": {
"bytes": 13255,
"sha256": "30d514155ec0e88a68e62089cd50b7747924a81095c957aa67b1bf5a70ac18f8"
},
"geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13581,
"sha256": "14dc1304822e74f8c7e0146a02af69ea39dc90d0d655a75b97383644c04b8900"
},
"geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"geometry/manifest.json": {
"bytes": 8099,
"sha256": "022fa0f307f9fb92fccbbc139637c62f40d1dcc3a4ea555a35c6b08d82bdb3b5"
},
"geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"geometry/two_containers_reversed_children-after.png": {
"bytes": 13950,
"sha256": "1536fa9da0fa89a64b12e7faf6d0dab1c3fa0177517e39fd1adaeaee3f2214fe"
},
"geometry/two_containers_reversed_children-before.png": {
"bytes": 14076,
"sha256": "2f3a2d55d30ff206d9daf9b8f84ba0e960332a02275289c66ab2e104da2e890e"
},
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14126,
"sha256": "2483bf404953ce9b3da38f2adca10c4e02e34638e2999acae7beecb5fe936a83"
},
"tooling/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"tooling/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
},
"tooling/auto-layout-format-precommit-20260925.json": {
"bytes": 364,
"sha256": "29c93825b415e04204d3fe23a85eef0798560bbb5a1a169689326602f65a9f35"
}
},
"archive": {
"name": "probe-e7deea70.zip",
"bytes": 900995,
"sha256": "c52f82d4782cd6a7f8cbe67498c8b2371e99204a65976aa8bcbbd0a86f835069"
}
}
@@ -1 +0,0 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -1,398 +0,0 @@
{
"scope": "Target-join candidate experiment, not production or native acceptance",
"runs": [
{
"run": "02-terminal-join-tests",
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
"exit_code": 0
},
{
"run": "03-terminal-join-probe",
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
"exit_code": 0
},
{
"run": "04-terminal-join-clippy",
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
"exit_code": 101
},
{
"run": "05-terminal-join-clippy",
"source_commit": "08656b18bf8934cf264469cf68fc6dea97c15cbb",
"exit_code": 0
},
{
"run": "06-terminal-join-probe",
"source_commit": "08656b18bf8934cf264469cf68fc6dea97c15cbb",
"exit_code": 0
}
],
"observer_lint_cleanup_output_byte_identical": true,
"post_run_probe_binary": {
"bytes": 24156160,
"sha256": "3541618adc25d12ca136941e973f506cc11bc556840193023d4295c27be758a5"
},
"members": {
"02-terminal-join-tests/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"02-terminal-join-tests/command/context.json": {
"bytes": 3658,
"sha256": "6d8d90920415df092df40afb4031fdbd12d2bc87a0daebea692b9f9288804783"
},
"02-terminal-join-tests/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"02-terminal-join-tests/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"02-terminal-join-tests/command/output.log": {
"bytes": 18709,
"sha256": "f024aaba0fcb680d02d49b5afde398453cf5183a08b561ff96e4c9a42cf70a17"
},
"02-terminal-join-tests/command/result.json": {
"bytes": 4321,
"sha256": "4b56d6ac30cc87ba7c7757906a3d0258e056178528b56c77312bd9675ce579f3"
},
"02-terminal-join-tests/command/stderr.log": {
"bytes": 990,
"sha256": "73f8f63d3339affe4bf6b47408a2ed020aca62606dc14faa03be3f094550eccf"
},
"02-terminal-join-tests/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"02-terminal-join-tests/orchestration.log": {
"bytes": 179,
"sha256": "3c673d3e29089ce517cd6026946443f9ae8fcba2fccb384835fffe2e8e19b58d"
},
"03-terminal-join-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"03-terminal-join-probe/command/context.json": {
"bytes": 3502,
"sha256": "380e3e8fae97e1ee75417c1efc3ee64bdca1958aa61caa1766fba86a6c7e52d3"
},
"03-terminal-join-probe/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"03-terminal-join-probe/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"03-terminal-join-probe/command/output.log": {
"bytes": 371192,
"sha256": "f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f"
},
"03-terminal-join-probe/command/result.json": {
"bytes": 4166,
"sha256": "57a1f866b2cb67880decd26becf3ac2e7715e38bbd26d3089c47dd62294afa4f"
},
"03-terminal-join-probe/command/stderr.log": {
"bytes": 278,
"sha256": "686a3d705aa21b73652e7589b1fa44094bbbc05f3118b2886161e0f815c8a334"
},
"03-terminal-join-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"03-terminal-join-probe/orchestration.log": {
"bytes": 179,
"sha256": "bf0516c97a7f3003b29a549f463458f3dc5516b1f41af024e9cf7f6062b9280b"
},
"04-terminal-join-clippy/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"04-terminal-join-clippy/command/context.json": {
"bytes": 3521,
"sha256": "9f20479acb398ab0dc3c35708ddaef39e4457fcc22f910e13342163718d61fc0"
},
"04-terminal-join-clippy/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"04-terminal-join-clippy/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"04-terminal-join-clippy/command/output.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"04-terminal-join-clippy/command/result.json": {
"bytes": 4185,
"sha256": "fe9e21a9e203fa0ecfeed957041faa22180287a2ecd158f8a7e77b881ccffc1b"
},
"04-terminal-join-clippy/command/stderr.log": {
"bytes": 2728,
"sha256": "e375843af8e5bb8e921e78b7e7fca844787d6785710506f5e2c5c8b6788beb59"
},
"04-terminal-join-clippy/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"04-terminal-join-clippy/orchestration.log": {
"bytes": 182,
"sha256": "949915299dd53b9c59b5116da6f163973cc339d5ae3eb3b1a73151065f68bd6e"
},
"05-terminal-join-clippy/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"05-terminal-join-clippy/command/context.json": {
"bytes": 3521,
"sha256": "15bd08c0a37dc3e01a0d046b6cd1341aa11bfc858b8da92ad20512e8401e8815"
},
"05-terminal-join-clippy/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"05-terminal-join-clippy/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"05-terminal-join-clippy/command/output.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"05-terminal-join-clippy/command/result.json": {
"bytes": 4182,
"sha256": "6970eff6a4d9741e27acdb2ef2bfceefcd122c1590741edeb7a112f4f5c357d4"
},
"05-terminal-join-clippy/command/stderr.log": {
"bytes": 177,
"sha256": "5be2ed4d5b119d9b42e2b1e874e3c9e2d6b27cc0610c7d2300760f51a3dccdbe"
},
"05-terminal-join-clippy/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"05-terminal-join-clippy/orchestration.log": {
"bytes": 180,
"sha256": "dc27f63c6f1e1ea3c1e6ff6dac85cf49d5927f6784ee768c3c12b1e8ec62848f"
},
"06-terminal-join-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"06-terminal-join-probe/command/context.json": {
"bytes": 3502,
"sha256": "5500c31ead4f64132a628646a9863f587e59ef8281a74a70fcff9a038c283200"
},
"06-terminal-join-probe/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"06-terminal-join-probe/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"06-terminal-join-probe/command/output.log": {
"bytes": 371192,
"sha256": "f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f"
},
"06-terminal-join-probe/command/result.json": {
"bytes": 4166,
"sha256": "bd3b20390a03ed7c637586119e12e0e55949303f9b17f6e018f231b1a9095833"
},
"06-terminal-join-probe/command/stderr.log": {
"bytes": 278,
"sha256": "8a49d76b8cf56f31f6877cb6baf9d9f82d5abfbc1bfcc2ae73b8d3ff209c482c"
},
"06-terminal-join-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"06-terminal-join-probe/orchestration.log": {
"bytes": 179,
"sha256": "e85db49cd4d73dbff0b45f92cfb96016f743db3e64878ceeee078515e7fe324d"
},
"geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"geometry/crossed_bipartite-before.png": {
"bytes": 13406,
"sha256": "aa3ba4f8ab67f6cd63d1c31fe309786e139db78ec6a36a0b00e8a854b590fe0c"
},
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13855,
"sha256": "e3cc0a326a2c8b577e40101c5f67ea9c3182bca6d3f0498cdc1f25a64df57b90"
},
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"geometry/manifest.json": {
"bytes": 8099,
"sha256": "0102449f730651a92233c4ae959e95e0a58036fe2b1c309224558c496241c741"
},
"geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"geometry/two_containers_reversed_children-after.png": {
"bytes": 13955,
"sha256": "1722ff21eaadd831e00b2176d61f8fa65b083d2fd5b633a196a3335d48ca125e"
},
"geometry/two_containers_reversed_children-before.png": {
"bytes": 14080,
"sha256": "78e765c579dd317e26177d0cd05cccc61519638e9198fdd0d344d9b54a95c1ba"
},
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14134,
"sha256": "ce6bc93dc38fe5b25552c8ebc5e778da175df53992e6a70ded8377fd99372587"
},
"support/auto-layout-j-comparison-20260925.json": {
"bytes": 76669,
"sha256": "3d5435686c2d23e97f08340693015ef66d1127726c9b5b5212678f43b3ad6b76"
},
"support/auto-layout-contact-audit-result-20260925.json": {
"bytes": 104481,
"sha256": "ec94203f42782d87c0459c251ab226567818e2715bc46a3e9ee0c25a6c15d620"
},
"support/auto-layout-contact-audit-20260925.py": {
"bytes": 9838,
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
},
"support/auto-layout-format-j-20260925.json": {
"bytes": 203,
"sha256": "5bd0e4b979aedf21bd38e4c41a1521dafffb78c3cccb61cd12dad56d4f4699e9"
},
"support/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"support/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
}
},
"archive": {
"name": "terminal-join-08656b18.zip",
"bytes": 3178939,
"sha256": "bd2146237353af05b8667dc7bd728007143a2f1b24ad9f8728fdbc50ffb3368e"
}
}
@@ -1 +0,0 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -1,565 +0,0 @@
{
"scope": "Finite PL/L experiments; no production/native/performance acceptance",
"runs": [
{
"name": "08-lane-tests",
"source_commit": "d0be9ff0674373fcf9623daf62bbf50dad02c4df",
"exit_code": 0
},
{
"name": "09-penalty-lanes-probe",
"source_commit": "d0be9ff0674373fcf9623daf62bbf50dad02c4df",
"exit_code": 0
},
{
"name": "10-lanes-core-tests",
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
"exit_code": 0
},
{
"name": "11-lanes-probe",
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
"exit_code": 0
},
{
"name": "12-lanes-clippy",
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
"exit_code": 0
}
],
"post_run_l_probe_binary": {
"bytes": 24202240,
"sha256": "3c6a6fd09bc86e7e6b3ff1ace05540c103393d66bbb02c46bf0ebd6214fbabb1"
},
"members": {
"08-lane-tests/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"08-lane-tests/command/context.json": {
"bytes": 3478,
"sha256": "7f30e52a87c964d86e86229061be72372a9cfc1a3fad9a37c326370c38aec4ad"
},
"08-lane-tests/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"08-lane-tests/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"08-lane-tests/command/output.log": {
"bytes": 670,
"sha256": "1b3cc48bee9bb4d564f0479a692b7b20fa6df5da3b8dccfda5d1487b6b93f53e"
},
"08-lane-tests/command/result.json": {
"bytes": 4121,
"sha256": "9a48e66ce638944e885e708b3f361ce2d099352e154536a46fafa6bca49af12f"
},
"08-lane-tests/command/stderr.log": {
"bytes": 304,
"sha256": "c534ac6e8df5add7c08f663cd516b9a0da947a93127ebda6c378ede9bd42f575"
},
"08-lane-tests/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"08-lane-tests/orchestration.log": {
"bytes": 170,
"sha256": "bf1ebdbbdd1955bd7b874592340e3d79a48a145a9b39faec898aaa807133f81a"
},
"09-penalty-lanes-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"09-penalty-lanes-probe/command/context.json": {
"bytes": 3502,
"sha256": "4c95894559f60d51fda0e2af09b2ec66abf9dc687d623c1e67c9e042747d0084"
},
"09-penalty-lanes-probe/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"09-penalty-lanes-probe/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"09-penalty-lanes-probe/command/output.log": {
"bytes": 371062,
"sha256": "04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd"
},
"09-penalty-lanes-probe/command/result.json": {
"bytes": 4166,
"sha256": "538aa79bcedd4cf646c63d5309ec738be4676e2045715db1035a4f334a536117"
},
"09-penalty-lanes-probe/command/stderr.log": {
"bytes": 279,
"sha256": "126be48ed1535d641835bd72b6fc5aa05a9a2120dd2012daa3e30108eb1703e2"
},
"09-penalty-lanes-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"09-penalty-lanes-probe/orchestration.log": {
"bytes": 179,
"sha256": "4e398b4fed1ac76d6bd61cb18fe2c50cae2764f040d878006e464c5728428cd3"
},
"10-lanes-core-tests/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"10-lanes-core-tests/command/context.json": {
"bytes": 3655,
"sha256": "2ee756c13c33bccf0cb7c87492bb62be5d5203044a066af0af36389059b2181c"
},
"10-lanes-core-tests/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"10-lanes-core-tests/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"10-lanes-core-tests/command/output.log": {
"bytes": 19032,
"sha256": "bde8202db1c2f3f407a7dcbf6a1184830d0914e2bbba0e5f7cbd2c55d72d56b4"
},
"10-lanes-core-tests/command/result.json": {
"bytes": 4312,
"sha256": "828871867eb7ff0ccfd5953a694ae594ae145e89bf2eca831368297d1ea9b874"
},
"10-lanes-core-tests/command/stderr.log": {
"bytes": 990,
"sha256": "df86da47eb1884669f1d0ce14107713ea9afd9e3cbb68becf451a018a1bf7303"
},
"10-lanes-core-tests/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"10-lanes-core-tests/orchestration.log": {
"bytes": 176,
"sha256": "6a2f55638fd26b60333bcd61cc1faaa29baaf9041962cbc1cfacd762bfc933e5"
},
"11-lanes-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"11-lanes-probe/command/context.json": {
"bytes": 3494,
"sha256": "d8ec80836b09c1859b7d482dbd2ebb0243495be3e022ce2cb5dcc5c47e9464bf"
},
"11-lanes-probe/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"11-lanes-probe/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"11-lanes-probe/command/output.log": {
"bytes": 371182,
"sha256": "64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d"
},
"11-lanes-probe/command/result.json": {
"bytes": 4142,
"sha256": "feee84c2fde115c22ea865033ff2d136da2aace1f1c8a7423c8add11358366a8"
},
"11-lanes-probe/command/stderr.log": {
"bytes": 278,
"sha256": "2e73f2722528e8f80b9e64f722643769e279d822835e9ea47e96cb07eaf51162"
},
"11-lanes-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"11-lanes-probe/orchestration.log": {
"bytes": 171,
"sha256": "93c3867e1dc8b07314a7ac03db0d76b641eda2eaad1ad58a61914f1d6ec64794"
},
"12-lanes-clippy/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"12-lanes-clippy/command/context.json": {
"bytes": 3513,
"sha256": "eb644e36413cc55e61b7f6aa6162f7f17f21f67911123f951f1ed96c91b30430"
},
"12-lanes-clippy/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"12-lanes-clippy/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"12-lanes-clippy/command/output.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"12-lanes-clippy/command/result.json": {
"bytes": 4158,
"sha256": "ea20c2e64c26667f575b70b598a790aceb1804070c208e5f8f1dd7839e8b0a8f"
},
"12-lanes-clippy/command/stderr.log": {
"bytes": 177,
"sha256": "5e1eff044f676ea902db61f76e53375f034cc2cd33c8671a56d11dd4a2aa2936"
},
"12-lanes-clippy/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"12-lanes-clippy/orchestration.log": {
"bytes": 172,
"sha256": "44d905169275ce11c8f66e16ce232d750f6b2701e6fb085880e9ad013219d18b"
},
"pl-geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"pl-geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"pl-geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"pl-geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"pl-geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"pl-geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"pl-geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"pl-geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"pl-geometry/crossed_bipartite-after.png": {
"bytes": 13163,
"sha256": "bb809e93b44e802d05430903cf397618fb901efdb6c5ab272574064e20641af6"
},
"pl-geometry/crossed_bipartite-before.png": {
"bytes": 13399,
"sha256": "9b7af6a43ec655cdcb05da49b5fffea661d4f5c9a5ae70a0c74c6e7696b066d3"
},
"pl-geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13856,
"sha256": "c386b537f077f014e73e99831fdbb57e64ae9709a30afd2909dd50d7443c1899"
},
"pl-geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13368,
"sha256": "bdcf079498dc2dce5245e47eac8038d736cea7af6176ada13bf682671c70b4b4"
},
"pl-geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"pl-geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"pl-geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"pl-geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"pl-geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"pl-geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"pl-geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"pl-geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"pl-geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"pl-geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"pl-geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"pl-geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"pl-geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"pl-geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"pl-geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"pl-geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"pl-geometry/manifest.json": {
"bytes": 8099,
"sha256": "dc9c09882d841e6ba050caabf411de8dd0e868879fe8f0b7a1b44cece9ffde8b"
},
"pl-geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"pl-geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"pl-geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"pl-geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"pl-geometry/two_containers_reversed_children-after.png": {
"bytes": 13957,
"sha256": "b0911f8afb39313e6ce43661396d6553276d5db53c659937acf87252ed502c6e"
},
"pl-geometry/two_containers_reversed_children-before.png": {
"bytes": 14083,
"sha256": "2d42d34af4674bbf1739e85967d743e6fc78c117ef1e7645724c504b006ee881"
},
"pl-geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"pl-geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"pl-geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14136,
"sha256": "f690678d5697cbec20e64bf92a128a8fd3a1dffe3948fcbe75ad99a4f33de96d"
},
"support/auto-layout-pl-comparison-20260925.json": {
"bytes": 75815,
"sha256": "81f57e651a8840aaaeacc085df2eb90174b2e494182f6cd40ccd6d50e7bb531e"
},
"support/auto-layout-pl-contact-audit-20260925.json": {
"bytes": 103918,
"sha256": "60ce7e9735ceef50a92d29a0414aafe3d8fb6174dab99eff6397e2abc88e0afa"
},
"support/auto-layout-pl-binary-20260925.json": {
"bytes": 220,
"sha256": "00f0ceb0e92a156de2d870e32b1d57d88465e5acedd9c5f5e733f183a750c46e"
},
"l-geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"l-geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"l-geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"l-geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"l-geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"l-geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"l-geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"l-geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"l-geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"l-geometry/crossed_bipartite-before.png": {
"bytes": 13399,
"sha256": "9b7af6a43ec655cdcb05da49b5fffea661d4f5c9a5ae70a0c74c6e7696b066d3"
},
"l-geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13856,
"sha256": "c386b537f077f014e73e99831fdbb57e64ae9709a30afd2909dd50d7443c1899"
},
"l-geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"l-geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"l-geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"l-geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"l-geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"l-geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"l-geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"l-geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"l-geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"l-geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"l-geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"l-geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"l-geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"l-geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"l-geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"l-geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"l-geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"l-geometry/manifest.json": {
"bytes": 8099,
"sha256": "897b9d42b494bac1e5263a8bab42756c3038403948e6ac76028d86fd6e56ae20"
},
"l-geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"l-geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"l-geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"l-geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"l-geometry/two_containers_reversed_children-after.png": {
"bytes": 13957,
"sha256": "b0911f8afb39313e6ce43661396d6553276d5db53c659937acf87252ed502c6e"
},
"l-geometry/two_containers_reversed_children-before.png": {
"bytes": 14083,
"sha256": "2d42d34af4674bbf1739e85967d743e6fc78c117ef1e7645724c504b006ee881"
},
"l-geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"l-geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"l-geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14136,
"sha256": "f690678d5697cbec20e64bf92a128a8fd3a1dffe3948fcbe75ad99a4f33de96d"
},
"support/auto-layout-l-comparison-20260925.json": {
"bytes": 76659,
"sha256": "e1e23e6c2a50cd384457bb061d5b70a740f586f42767164fad9703ecbb4096a8"
},
"support/auto-layout-l-contact-audit-20260925.json": {
"bytes": 103893,
"sha256": "6f6cc674c27d3f43001fe1751ef3b09332caa9ddca396759f5525f811cbe1aaf"
},
"support/auto-layout-l-binary-20260925.json": {
"bytes": 220,
"sha256": "9c6d6e20c86237e5d1b917a981f2a5a8612d1c58b6e0706d4701e6c7cc59e06f"
},
"support/auto-layout-contact-audit-20260925.py": {
"bytes": 9838,
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
},
"support/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"support/auto-layout-format-j-20260925.json": {
"bytes": 203,
"sha256": "5bd0e4b979aedf21bd38e4c41a1521dafffb78c3cccb61cd12dad56d4f4699e9"
},
"support/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
}
},
"archive": {
"name": "lanes-e8ec6db.zip",
"bytes": 3518507,
"sha256": "5512b4cbd99e3bf03eb975e25fb980f7b1a95a5cb19f3687fb3d6d83d1839e8f"
}
}
@@ -1 +0,0 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -1,223 +0,0 @@
{
"source_commit": "3d7adff923dee5bed54dfdccc119dbee0c7c2773",
"scope": "Transient P coefficient3.0/cap80 experiment, not production acceptance or claim that J tests pass with P.",
"post_run_probe_binary": {
"bytes": 24156160,
"sha256": "8f3ac5aa1fa01be6a8ab664e8ae269f6527b8ffb7e326c2926c8fae7c3d7e366"
},
"members": {
"run/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"run/command/context.json": {
"bytes": 3504,
"sha256": "6f6019b2be69e12e3270d8570e9e4950c93e42e8b3093a0e0324a30f7e5eb0ff"
},
"run/command/inputs-after.json": {
"bytes": 1727969,
"sha256": "607febcd0d74d11deaa07a44b8b9cf6c382fd65d55deadb2d8ac7e889797dcf1"
},
"run/command/inputs-before.json": {
"bytes": 1727969,
"sha256": "607febcd0d74d11deaa07a44b8b9cf6c382fd65d55deadb2d8ac7e889797dcf1"
},
"run/command/output.log": {
"bytes": 371606,
"sha256": "13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7"
},
"run/command/result.json": {
"bytes": 4172,
"sha256": "6149122d05d77e02b463edb3dd359b06786bc4468c27d8cd625cbc1bc80c9894"
},
"run/command/stderr.log": {
"bytes": 279,
"sha256": "fe5d8d303700ef5b92bfaa95ac1f99a2214e1fc5f6c5ac8d83f6303aa258965b"
},
"run/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"run/orchestration.log": {
"bytes": 181,
"sha256": "db5af22d893966919b9342fd06b99e7e1c82c5c87593544b7762cc85f9a7e45a"
},
"geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"geometry/crossed_bipartite-before.png": {
"bytes": 13413,
"sha256": "8622726dfdfc01e93fcd2d9d22c6d082e5a169b9dcd59f788e876954431214fd"
},
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13855,
"sha256": "e3cc0a326a2c8b577e40101c5f67ea9c3182bca6d3f0498cdc1f25a64df57b90"
},
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"geometry/manifest.json": {
"bytes": 8099,
"sha256": "c1b59384878e519efec99757efee571635f30d814247db2f183eebbf9c467a0f"
},
"geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"geometry/two_containers_reversed_children-after.png": {
"bytes": 13955,
"sha256": "1722ff21eaadd831e00b2176d61f8fa65b083d2fd5b633a196a3335d48ca125e"
},
"geometry/two_containers_reversed_children-before.png": {
"bytes": 14092,
"sha256": "dcbc521b8e5efd6a201da8a724ed218a9f1331a8abb2eda299a5807828037cb9"
},
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14134,
"sha256": "ce6bc93dc38fe5b25552c8ebc5e778da175df53992e6a70ded8377fd99372587"
},
"support/auto-layout-p-comparison-20260925.json": {
"bytes": 77494,
"sha256": "9f228fbe78e1888c5d93e87dddd8d2effc01bab723929a87423c61e23f5cad66"
},
"support/auto-layout-p-contact-audit-20260925.json": {
"bytes": 104912,
"sha256": "6f4add5c81f6d16c45efabbefd9e36c9beb637b6823993f0d51adc3e20485ad9"
},
"support/auto-layout-contact-audit-20260925.py": {
"bytes": 9838,
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
},
"support/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"support/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
}
},
"archive": {
"name": "penalty-3d7adff.zip",
"bytes": 916568,
"sha256": "6b819b01c8012aa72d423443f4dc04ae261f1ee9dc6907f0063c219ff173ad36"
}
}
@@ -1,61 +0,0 @@
# #32 Auto-layout source and evaluator map
Read-only inspection of `.local/auto-layout-20260925`, base715036e132677dd2bc2fb37ed316d93dc9987aec, on2026-09-25. Issue32 explicitly asks automatic creation/removal of bends, attention to connection intersections and labels. No source changes, compiler, GUI, model helper or Gitea writes were performed. No geometric outcomes below are claimed as measured results.
## Actual surfaces and shared execution
- `crates/oa-desktop/src/views.rs:443`: saved Architecture diagram toolbar **Auto-layout** sends `Message::Command(Command::Layout(id))`. `model_menu.rs:417`: background **Arrange elements** sends the same command. The generic chooser excludes Scenario, not State, but normal State navigation routes to its dedicated workspace. `behavior/state_menu.rs` returns early for the dedicated State menu, and `state_view.rs` has no equivalent Auto-layout button. State view creation still calls shared Layout (`behavior/state_edit.rs:361–410`); behavior creation batches Layout too (`behavior/creation.rs:477–504`). Distinguish exposed UI from callable core behavior.
- `crates/oa-core/src/model.rs:1431`: saved projection kinds are Overview, Decomposition, Allocation, Traceability, FunctionalDataflow, Capabilities, StateMachine and Scenario. `session.rs:947` accepts the first seven; Scenario explicitly refuses and requires its separate geometry operation. Process topology and Scenario lane/message arrangement are separate behavior canvases, not this generic command.
- Allocation **Arrange next drag / Alt+A** is a different manual translation workflow (`allocation_drag/arrange.rs`, `app/allocation_drag.rs`, `diagram/work_drag.rs`). Do not silently turn it into automatic graph layout or change its allocation/group/refusal/Undo contracts merely because its label contains Arrange.
- `app.rs:3559` applies pending property edits and remaps a changed diagram identity before executing Layout; preserve that admission/identity behavior (`tests.rs::placement_identity_edit_then_drag_and_diagram_identity_then_arrange`). `document.rs:322` prepares/validates a candidate, updates the source bundle with identity provenance, then commits one model/source history entry. Core Session execute at`session.rs:275` likewise records one changed candidate; Undo/Redo swap exact Projects and no-op candidates create no history.
- REST transactions at`crates/oa-server/src/routes.rs:1011–1041` accept serialized Command batches including Layout under expected-revision admission, with dry-run and atomic PreparedProject/store commit. Core behavior therefore cannot rely on desktop-only fonts/state. `docs/v2-interface.md` lists Layout convenience commands. CLI exposes check/lint/stabilize/rename-alias, not a direct layout verb. Text/source may store explicit node/route records; parsing/loading them must not implicitly auto-arrange.
## Current algorithm and why the issue is real
`session.rs::layout` measures a projection-parent forest, vertically stacks children below headers, and puts roots into rows of four. Roots use an exchange-aware topological-like ordering with alias/ID tie breaks and deterministic cycle fallback. Child order is placement-ID order. It changes node positions/sizes, computes per-node deltas and calls `projection::translated_routes`; it neither scores routed geometry/labels nor generates or removes stored waypoints.
`projection.rs:81` supplies actual visual parents: nearest placed semantic ancestor; Allocation derives performer grouping from allocation summaries; Traceability is flat; State filters the machine. Ports have owner placements, not independent node placements (`edge_endpoint_placements`). Measurement reserves minimum sizes, State action/internal rows and port footer (`session.rs:967–1006`). Folded descendants still belong to the authored forest; projected visibility and stored layout are distinct.
The router is **not unaware of crossings or labels**: `routing.rs:457` routes stable edge IDs with a bounded search and previous-edge costs; `crossing_cost:990` penalizes proper crossings and positive collinear overlap separately. All paths settle before automatic label placement; `label_geometry`/`label_collisions:1370–1552` consider node obstacles, earlier labels and all visible strokes. But routing remains greedy, has finite search budgets, and authored label placement bypasses avoidance. Auto-layout never feeds these costs back into node order/spacing. Existing pins constrain paths even after node arrangement, except folded/promoted routes temporarily suspend their custom geometry. Thus a node-only Layout plus pinned greedy routing cannot promise the joint improvement requested by32.
Base715 uses scalar-estimated label rectangles. The separate #36 measured State multiline layout is not present in this base; do not assume its geometry or acceptance has already integrated. Ordinary labels, association-end labels/stereotypes and State labels also differ in presentation. Parent should coordinate routing-file overlap with #36 before integration, not silently reimplement its measurement policy.
## Contracts requiring an intentional change
1. `harness/release-routing-contract.md:143–146` explicitly says Layout preserves pins, translating only equally moved endpoint owners, with Reset routing separate. `crates/oa-desktop/src/guide.rs:360` repeats **Auto-layout preserves pins**. These are directly incompatible with the user's requested automatic bend removal/generation and must be revised for the explicit whole-view operation, with Undo restoring prior authorship.
2. `crates/oa-core/tests/release_routing.rs::layout_preserves_authored_route_count_order_labels_and_undo` fixes route list count/order, two pins on each route and exact labels. Replace only the superseded Layout assertions with the new declared output contract plus stronger geometry checks; retain unrelated-diagram exactness and exact Undo. Do not remove all route-preservation tests.
3. `state_diagrams.rs::layout_reserves_internal_rows_and_state_routes_retain_hard_pins` combines two things: the **pre-Layout** router must traverse authored pins without mutation; the post-Layout assertions reserve State rows and source roundtrip. Preserve those valid assertions, and rename/split the test if Layout no longer retains pins. Its current body does not actually assert post-Layout pin preservation.
4. Decide explicitly whether generated bends remain derived route corners or become persisted editable waypoints. The user asks visible automatic routing improvement, not necessarily a new semantic field. `routing.rs` documents only authored pins in the model; blindly storing every solver corner would turn generated geometry into hard constraints and can cause second-run drift. Whichever representation is chosen needs first/repeat Arrange and manual-after-Arrange tests.
5. Define scope for invisible/suspended routes, authored label offsets and explicit attachments. User32 authorizes changing bends; it does not automatically authorize deleting manual semantic-port metadata, every hidden route, or authored label placement. A narrow baseline is reset/rebuild bends for eligible visible edges while retaining attachments, labels and unrelated/hidden records; measure whether that suffices. If an authored label constraint defeats label clearance, report it or make its intentional reset policy explicit instead of pretending the layout is collision-free.
## Invariants to retain
Complete elements/relations/traces/types/names/text/IDs/containment/allocations/occurrences remain exact; only the selected diagram's declared presentation fields may differ. Other diagrams, node identities, collapsed flags, view options, unplaced elements and manual port side/fraction metadata remain exact. Automatic port geometry may change with node geometry, but semantic port identity/contract and explicit anchors do not. Existing tests `port_anchors::separate_views_resize_layout_and_hidden_owners_keep_manual_metadata`, `workflows` nested-parent containment, and desktop port/identity tests are relevant sentinels.
Keep move-one-end pins-fixed and move-both-owners equal-delta translation in `projection::translated_routes`, normal drag/reflow/group previews, reconnect, folding suspension/resumption, Hide/show and Reset routing unchanged unless separately justified. Keep finite geometry and existing point-count/attachment/fraction validation (`validation.rs:650–720`), deterministic bounded failure/fallback, source/JSON roundtrips, dry-run nonmutation, rejected-operation no-history, and exact one-step Undo/Redo. A Layout improvement must not trigger new allocation/reconnect semantics.
## Independent fixtures and falsifiers to freeze before candidate comparison
Use hand-declared topology, IDs and geometry; record the old candidate's metrics once, then compare materially different candidates against the same evaluator. Do not use a candidate's own cost function as the acceptance oracle.
| Fixture | Independent observable requirement |
| --- | --- |
| Two connected OA activities / SA functions with redundant dogleg and one blocking third card | Explicit Arrange removes obsolete turns; unobstructed edge straightens, blocked edge gains necessary orthogonal turns; semantic endpoints exact, no nonincident-node penetration. Include authored source/target attachments. |
| Two containers, each with two children, reversed child-order connections | A planar hand-constructed witness has zero proper crossings; require zero on this bounded case, child containment and preserved port contract. Detect current ID-ordered child stacking weakness. |
| Four-node diamond plus return edge, self-loop, parallel and reverse-direction edges | No false cycle/deadlock; meaningful separation of parallel paths; self-loop remains visible; distinguish shared endpoint fans from mid-path overlap. Test swapped UUIDs and stable semantic aliases. |
| Five-plus roots and disconnected component | Exposes current every-four-roots wrap and ordering discontinuity. No overlapping cards, reasonable route/area bounds and deterministic repeated result. |
| OA/SA nested Allocation with ports, uniform subtree, folded ancestor and hidden route | Child interiors below reserved headers/footer, anchors on owner boundary, no fabricated ports, no semantic reassignment; hidden-route policy explicit; other view exact. |
| Traceability mixed OA/SA with duplicate placement sentinels elsewhere | Flat visual graph stays flat, valid edge identities and other diagram exact. |
| State machine with composite State, region, entry/exit boundary, internal/action rows and self-transition | State-specific legal boundary crossings, row reservations and no overwritten semantic state; shared Layout initialization remains valid even without a State Auto-layout button. |
| Long ordinary/association labels, adjacent parallel labels, and #36 B/W/U State cases once integrated | Independently measure label/node, label/label and unrelated stroke/label intersections using actual displayed geometry; native ink/readability check separate from advance-box arithmetic. |
| Dense/nonplanar or contradictory-anchor stress case | Finite time/work and explicit residual warnings/metrics; no claim all crossings can disappear. Preserve exact Undo and input on refusal. |
## Metrics and acceptance discipline
Report a vector, not a single opaque beauty score: (1) hard invalid geometry/illegal obstacle penetration and sibling overlap area; (2) label-node/label-label intersection area and other-edge strokes entering labels; (3) distinct proper edge-pair crossings; (4) positive-length collinear shared segments; (5) bend count after duplicate/collinear simplification, path length/stretch and total view bounds. Define endpoint/ancestor exemptions before running: parent-child containment is intentional, a shared semantic endpoint is not a crossing, owner leads and legal State boundary crossings are not nonincident obstacle violations. Deduplicate segment-pair crossing events at the same physical point; count edge pairs separately. Count near-parallel clearance as a separate readability observation, not zero-width intersection.
Use independent rectangle/segment math and full projected/routed outputs; export SVG and canvas must agree with those outputs. Include authored and derived labels, including association ends. A zero-crossing result obtained by coincident overlapping paths, gigantic detours, clipping labels or hiding edges fails the other metrics. Set fixture-specific route/area ceilings from a feasible manually declared witness rather than arbitrary post-hoc thresholds. Compare a second Arrange for idempotence, input-order permutation for determinism, pure camera changes for model invariance, then source Save/reopen and exact Undo/Redo.
Unavoidable cases: nonplanar graphs cannot all be planar with distinct nonoverlapping edges; fixed attachment orders, nested boundaries, coincident semantic endpoints and required self-loops can constrain clearance. Existing authored labels can intentionally occlude nodes. Report constrained residuals honestly and avoid turning ordinary automatic layout into deletion of semantic edges or impossible universal no-crossing guarantees.
The first useful milestone is a finite fixture/evaluator plus an explicit bend/label/hidden-route policy, then a prototype compared against current Layout. No need to expand into unrelated Process/Scenario geometry or redesign manual Arrange drag for this issue.
@@ -1,39 +0,0 @@
# J terminal-join actual-results independent audit
Result: the finite experiment supports the terminal-cost asymmetry diagnosis, with a real ordinary-scene overlap regression retained below. It does not establish universally improved routing, complete readability, or #32 acceptance. Static audit only: no compilation, probe rerun, GUI, source edit or publication by reviewer.
## Evidence and checks
Tested pin `497c1ad8b39788148c5f03bc8542d6d8e28dbc01`, compared against first probe `e7deea7039bcf31675cffbb462cfeb19d62a7e20`. Run03 command `cargo run --locked --offline -p oa-core --example auto_layout_probe`, Windows x86_64-pc-windows-gnullvm/dev: receipt exit0, failure null, inputs unchanged. Independently verified receipt log hashes. Test02 at the same pin also exit0/unchanged: six summaries132+7+13+18+2+13 =185 passed, zero failed/ignored.
Independently parsed both raw JSONL outputs, rather than relying only on comparison-helper booleans: all37 variant Projects, complete projected nodes/ports, and per-edge first/last coordinates match exactly. Thus changed area is routed/label bounds, not changed node placement. Independently recomputed every raw pairwise axis-aligned collinear interval total in both runs (74 variant observations); all agree with emitted totals.
All nine candidate rows report supported, identical repeated input, idempotence, passes2–10 equal first and previous, exact JSON/canonical-single-source roundtrips, no associated errors. Conservation remains true except the intentional authored-detour route reset (`authored_routes_exact=false`). Exact old/new Projects additionally confirm J changed none of these model records. Existing Command::Layout history/Undo/Redo checks pass in all nine rows; the layered candidate remains a pure Project transformation with no candidate-command history evidence. No native GUI evidence.
## Complete changed quality-vector rows
| Fixture / variant | Raw sharing old→J | Nonterminal sharing old→J | Other changed fields |
|---|---:|---:|---|
| diamond / before |136→36|100→0|none|
| diamond / layered candidate |82→36|46→0|none|
| crossed_bipartite / before |730→872|658→800|bends5→4; length2076→2064|
| crossed_bipartite / layered candidate |344→187|272→115|drawing area165360→175960|
| two_containers_reversed_children / before |200→54|200→54|none|
| two_containers_reversed_children / baseline |148→18|148→18|none|
| two_containers_reversed_children / reset control |148→18|148→18|none|
These are all changes in the comparison's pre-existing12-field quality vector; the remaining30 rows are unchanged. All baseline/reset rows outside the two-container case are unchanged. Seven of nine layered candidate vectors remain unchanged. Raw strict proper crossings remain zero throughout these comparisons; no demonstrated proper-crossing reduction follows.
The crossed-bipartite BEFORE regression is substantive, not a metric artifact: independent interval sums confirm142 additional shared units. Fewer bends and12 shorter length do not erase that readability tradeoff. Layered bipartite improves157 shared units but retains115 nonterminal units and grows routed drawing area10600 (~6.41%). Viewed its actual offline PNG: distinct vertical channels remain joined to shared horizontal routes. This is not an unambiguous-trace acceptance result. Diamond's remaining36 units are the separately classified common terminal stubs.
The new point-contact metric has no v1 field to compare directly: do not interpret its mere introduction as newly created contacts. Current layered diamond records2 contacts and bipartite9; the independent contact worker's retrospective audit is pending at this review. Counts classify contacts and do not alone establish readability. Approximate core label bounds, missing renderer/port-label measurements, finite fixture families, axis-only grid state, sequential edge ordering and no global hard-pin optimization remain limits.
## Binding and recommendation
- Old raw output SHA256 `21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`.
- J raw output SHA256 `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
- Run03 result.json SHA256 `57a1f866b2cb67880decd26becf3ac2e7715e38bbd26d3089c47dd62294afa4f`.
- Comparison JSON SHA256 `3d5435686c2d23e97f08340693015ef66d1127726c9b5b5212678f43b3ad6b76`.
- Geometry manifest SHA256 `0102449f730651a92233c4ae959e95e0a58036fe2b1c309224558c496241c741`; all37 image byte lengths/SHA256 verified. These are offline geometry schematics, not native captures.
Recommendation: retain J as a successfully isolated scoring correction candidate, with explicit non-monotonic quality results. Before further penalty tuning, use the independently reconstructed contacts and the crossed-bipartite BEFORE regression as falsifiers for any stronger penalty/lane experiment. Keep exact Projects/nodes/ports/endpoints fixed and retain the entire vector, including labels and area. Do not advance directly to broad production quality acceptance based on the layered diamond improvement.
@@ -1,25 +0,0 @@
# Terminal-join experiment independent source review
Read-only review of the local candidate based on e7deea7039bcf31675cffbb462cfeb19d62a7e20; no compiler, probe, GUI or helper executed by reviewer. Reviewed routing.rs SHA256 43c2e983a132fd1c687706f5dc6b27867403aae2aa253cdc25195141d24759a5 and the accompanying v2 probe diff. Parent owns formatting, final source pin and execution receipts.
Recommendation: proceed with the bounded J experiment. No blocking defect found in the changed scoring or contact observer. This is source review, not test success or production acceptance.
- route_edge supplies the known target continuation only to the final leg, preserving intermediate hard-pin context. The final whole-path score remains unchanged; local selection does not persist or double-charge its score.
- fast_path applies the same incoming/outgoing join to both candidate estimates and actual costs. Its Manhattan + two-turn lower bound remains safe for genuine two-bend alternatives because joins/occupied-segment costs are nonnegative. Compacted zero/one-bend alternatives are already represented by the initial L candidates.
- grid_path charges the terminal turn before inserting target states into the queue. Manhattan remains an admissible and consistent lower bound for these nonnegative transition additions. Adding a charge after returning the first target would have been incorrect; this implementation avoids that trap.
- Zero-length spans retain the existing result and do not invent an arrival vector. turn_cost explicitly returns zero for a zero-length adjacent leg. Whole-route behavior around repeated pins remains covered by existing integration checks rather than a new optimization claim.
- New private tests exercise both fast and grid directly, four reflected/rotated diamond witnesses with independently stated complete cost310, absent outgoing context, straight continuation/reversal and degenerate spans. Full route pins, attachment metadata and preview/settled agreement still depend on the parent-planned existing suites; no passing result is inferred from their presence.
Important limits: grid states remain two axes, not four signed arrival directions, although turn_cost distinguishes reversals. This pre-existing state abstraction is not proof of globally optimal reversal-aware A*. The patch correctly incorporates target cost before arrival-state merging, but does not fix all possible intermediate state dominance issues. Fast routing is still preferred over grid whenever feasible; authored pins are solved leg by leg without global lookahead. Budget/obstacle fallback behavior is unchanged. These are not blockers to this finite asymmetry experiment, but must remain outside its claimed guarantee.
The probe contact metric is additive: closed point intersections deduplicate by edge pair and EPS-quantized coordinate, OR proper-crossing witnesses, distinguish endpoint/vertex/interior roles, and classify common terminals by both owner and physical coordinate without subtracting them. Positive collinear intervals remain in the separate shared-length metric; a noncollinear witness at their boundary can still count as a point contact. The analytic witnesses include proper, T, bend, endpoint, collinear-touch and overlap cases. These definitions are suitable for the finite orthogonal fixtures, not an exact general floating-point geometry theorem.
Execution interpretation: compare projected_nodes, projected_ports and exact emitted endpoints against the frozen first run before calling this a fixed-node experiment. The layered prototype itself reroutes while deriving spacing, so identical fixture input alone does not establish identical output placement. Preserve the full metric vector: replacing coincidence with point contacts/crossings or worsening labels must stay visible. No generic node/label layout or native traceability acceptance follows from this experiment.
## Formatting recheck and source identities
Original reviewed routing SHA256: `43c2e983a132fd1c687706f5dc6b27867403aae2aa253cdc25195141d24759a5` (measured by reviewer). Original evaluator SHA256: `b7e10e6d346bac93486b075229d8b5b4b74acba05b4bc5778cc60b89a7a6f4d3` (worker/parent-provided identity; reviewer inspected its actual diff).
Current formatted routing SHA256: `f482f6ef79ee0ef2c615a0ef7fff0d5ad0c56dd080efa8e374b7c29ab9961507`. Current formatted evaluator SHA256: `2cc8d3cb04f8a48bef02008e7b9a0d78aa254009ee85ef7d546df1d04f97ebca`. Both measured by reviewer. Reread full scoped `git diff --ignore-all-space` after formatting: scoring expressions, conditionals, witness coordinates/assertions and observer definitions agree with the pre-format reviewed output. Observed differences are wrapping/indentation and optional trailing commas in routing tests. There is no retained original-byte snapshot for a mechanical whitespace-only comparison; this is an independent source re-review, not a claimed byte-level proof.
Exact fixed-geometry comparators: per fixture and variant compare full `projected_nodes`, full `projected_ports`, and per-edge first/last coordinates in `routed_edges` with the frozen prior output. Compare endpoint owners to projected edge definitions, and preserve source/target attachment and semantic port identity/anchor metadata in the full Projects. New `route_endpoints` makes the current identity/coordinate association explicit; derive the prior coordinates from prior `routed_edges`, since v1 did not emit that new field. Inspect route/label changes only after those placement/attachment checks, and retain any mismatches as results rather than silently excluding fixtures.
@@ -1,19 +0,0 @@
# Boundary-order conservation review
Read-only audit of `.local/boundary-order-20260925/run01`, source `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`. No compiler, router, engine or native execution. Twenty boundary candidates are supported; zero unsupported cases. Fourteen current SCC controls and six paired extra-fixture baselines are accounted for separately, not counted as additional boundary cases.
Independent complete-Project reconstruction passes for all20 boundary candidates,14 controls and6 paired baselines. Reconstruction starts from raw original Project, resolves actual endpoint owners and preoperation reset eligibility, retains entire semantic/nongeometry structures, applies only permitted visible geometry/minimum restoration and hidden-owner translation, and compares the entire expected result. No conservation boolean substitutes for this comparison. All66 receipt hash/byte-size bindings read back exactly.
All14 current SCC-control Projects equal their prior SCCrun02 Projects exactly. All20 successful boundary/baseline pairs retain exact effective node sizes, per-group SCC membership/rank/canonical walk/grid/gaps, and rigid internal SCC geometry within0.001units. Eleven boundary Projects equal baseline completely. Nine differ: all six extra fixtures, two_containers_reversed_children, workshop original and workshop folded. Node positions are the intended variable; no semantic reparenting or new authored elbows are persisted.
Every authored port-anchor record, other diagram, route entry identity/order and nongeometry field remains exact. The only authored-route changes are the same three eligible waypoint/label resets (mixed, reversed mixed, authored_detour_and_label). No retained dormant/promoted authored-route translation or nonempty authored attachment coverage occurs; do not infer it from the checker implementing that policy. Folded workshop's three hidden descendants still independently follow Allocation/semantic ancestry under collapsed owner `75920e7a-4586-58b7-9eb2-7e0a3d8a1825` by(-680,0), preserving latent sizes/metadata. All checked non-State container enclosures/minima pass.
Automatic port changes are preserved, not normalized away: boundary_two_local_sccs has two side changes, owner`…000004`/port`…000026` Bottom→Right and owner`…00000a`/port`…00002a` Bottom→Left. Neither is authored. Every pair has identical projected port inventory; no other side changes were observed. These are actual projection results, not evidence that source anchor records changed.
All34 primary successful records report exact same-input output, all nine repeated calls2–10 equal first/previous, and exact JSON/single-source round trips. These remain recorded Rust checks: repeat Projects/source strings are not serialized for independent rerun. Exact intended node plans are absent; final-plan equality remains the source import gate. The audit independently checks final emitted projection, permissible full-Project deltas, component invariants and enclosures, not a second layout implementation. It does not validate renderer text, estimated label collision accuracy, trace readability, general native workflow or adoption.
Auditor: `.local/audit-boundary-conservation-20260925.py`, SHA256 `f14d96f7ee1487d245bd30436dea356df7524006c51f2fbac929b067b881d893`. Final result: `.local/boundary-conservation-audit-final-20260925.json`, SHA256 `f6a3fa93c03174e0eae6f816975f06a10a696659bd3fd58291ac805a69d5edee`. Raw paired rows are read directly and bound to original paths/hashes, with baseline selector attribution; no normalized copy is represented as runtime output.
The first audit output is preserved: it successfully checked conservation but grouped14 SCC controls with20 candidates and used prior baselines directly. Final checker explicitly labels those roles, compares controls to prior results and boundary cases to the current controls, while retaining six in-row baseline/boundary pairs. This is inventory/attribution refinement, not a suppressed model failure. Original SCC auditors/reviews were untouched.
Reproduce: `python audit-boundary-conservation-20260925.py RUN_DIRECTORY NEW_OUTPUT_JSON 3e21c1bca245944ae0ec7bb02aaa920f45f2cc30 PRIOR_SCC_RUN02_DIRECTORY`. UTF-8 is explicit; output refuses overwrite; only the Python checker executes.
@@ -1,81 +0,0 @@
# Boundary-order design critique
Local-only independent design review, 2026-09-25. Read source at `f4fa0c11f2271a93e324541e570ba391dce8122f` in `.local/auto-layout-20260925` and the SCC experiment's results, run02 quality review and transfer diagnosis. No implementation, build, router execution, GUI exercise or Gitea publication. The working tree was clean when inspected. This is a proposal and source-derived reasoning, not new empirical quality evidence.
## Recommendation
Use one deterministic sweep over the SCC condensation of **ordering dependencies between sibling groups**, starting from the complete canonical SCC plan. A dependency must represent every mutable ancestor ordering that can move an external source endpoint. Do not substitute source-parent dependencies, parent ID order, absolute-X order, or a fixed count of snapshot passes. Freeze the internal decision state of a cyclic dependency SCC: compute its members' proposed orders from one pre-SCC snapshot and commit all together. Explicitly document that cyclic dependencies can retain or exchange crossings; this is a bounded heuristic, not a cycle solver.
Preserve the existing semantic SCCs, ranks, member walks, perimeter offsets, block dimensions, gaps and root ordering. Repack the changed ordinal orders from the same block dimensions. Group envelopes are invariant under this operation; assert that fact instead of introducing a new enclosure growth pass. Import only the final plan using the existing exact projection and mandatory-lead guards. This adds precisely the information omitted by the current child-group planner while retaining the sparse structural witness.
The selected policy preserves same-rank undirected-connected bundles as indivisible ordering units with their canonical BFS internal order. A new external-order pass must not silently undo that proximity policy. Use visible endpoint centers as a declared heuristic, and retain final port/route checks; do not pretend center ordering proves attachment alignment or readability.
## Why the alternatives differ
| Candidate | Main benefit | Concrete weakness | Verdict |
| --- | --- | --- | --- |
| One canonical snapshot, incoming only | Smallest change; no mutation-order dependence; handles the two-container witness | A→B→C chain: B changes order to A, but C sorts against B's stale canonical order | Useful control, too weak as the preferred next candidate |
| Fixed number of snapshot passes | Carries influence farther without traversal code | Any fixed count has a longer-chain counterexample; cyclic groups may alternate; the pass count becomes an arbitrary hidden bound on quality | Reject as a generalization of old layered's three passes |
| Parent-ID or X/topological order using only parent relations | Cheap sequential propagation | Source descendants can later move under an ancestor ordering; ancestor-level SCC perimeter X does not express causality; unrelated ID changes select winners | Reject as the dependency definition |
| Complete ordering-dependency SCC sweep | Acyclic influence propagates once; explicit handling of genuine mutual dependence; bounded work | More bookkeeping; cyclic-SCC snapshot retains a declared limitation | Preferred bounded experiment |
| Joint crossing minimization or repeated barycenter optimization | Could optimize opposing constraints and port attachment geometry | Introduces a substantially different optimization problem, objectives and stopping policy before the simple witness is resolved | Defer until evidence defeats the bounded structural candidate |
Incoming-only treatment is meaningful because it anchors downstream order to upstream arrangement. It does not by itself remove cycles: two containers can each have an incoming edge from the other even when their internal child graphs are edgeless. The SCC used for ordering dependencies is distinct from the sibling-subtree semantic SCC already used for rank and perimeter placement. Never merge these concepts or feed ordering dependencies into semantic ranks.
## Precise candidate contract
1. Run the existing canonical planner to an in-memory plan. Keep a record for each sibling group of its SCC blocks, ranks, canonical ordinal order, dimensions, cut gaps and member offsets. Keep the root order fixed. Record a complete canonical absolute-position snapshot without importing an intermediate Project.
2. A target ordering group G is the children of a visible, noncollapsed parent P. An eligible boundary signal is an oriented **projected** edge for which the target lifts to a child of P and the source does not lift to any child of P. Internal-group incoming links are not boundary signals; outgoing and undirected boundary links supply no ordering signal in this candidate. An edge to a hidden endpoint uses its actual projected promoted endpoint, never the latent hidden placement.
3. The unit that moves is an SCC block, or an explicitly defined contiguous undirected-connected bundle of same-rank blocks. If bundle support is deferred, freeze layers with any such cross-block undirected link and report the reason. Do not break an SCC or reorder its perimeter members. A unit is anchored when at least one eligible incoming boundary signal targets one of its members or visible descendants.
4. For each same-rank layer, preserve the canonical ordinal indices occupied by unanchored units. Sort anchored units only into the remaining indices, by the arithmetic mean of their external source endpoint centers' absolute Y coordinates, followed by the existing canonical unit key. Deduplicate external visible source placement IDs per unit; several ports or parallel relations from one source owner contribute once. Sort those placement IDs independently of relation IDs, accumulate in f64, and reject nonfinite values. This is a declared source-owner weighting policy: relation multiplicity does not increase influence. This score is a center-based ordering heuristic, not a crossing objective.
5. Build a dependency graph whose vertices are the nonroot ordering groups that can alter an order. For every eligible signal consumed by G from visible source S, add H→G for **every** mutable group H whose child subtree contains S. In other words, include all ancestor ordering transforms that can change S's absolute position, not merely S's immediate sibling group. A collapsed visible source has no visible interior ordering group; its visible ancestors still matter. Conservative extra dependencies are permissible if reported, but may enlarge SCCs and freeze useful propagation.
6. Condense that graph. Process dependency SCCs in deterministic topological order. Before each SCC, reconstruct a complete absolute-position snapshot from the current relative offsets. All groups inside that SCC read this same snapshot, calculate proposed orders, then commit their orders together. Acyclic singleton SCCs therefore observe completed upstream changes; cyclic SCCs take one simultaneous bounded step. Independent ready SCCs cannot influence each other's consumed sources by construction, but use the canonical key to make diagnostics reproducible.
7. After committing an order, repack by prefix sums of the unchanged block heights and unchanged gaps. Preserve rank X origins and internal block/member offsets. Recompose absolute descendant positions from all relevant relative transforms. Do not move only the source node while leaving its descendants behind.
8. Assert every group's planned envelope and every block size equal their canonical values. Assemble one final complete plan and call the existing importer once. Keep original-to-final route translation, eligible reset, dormant-route preservation, authored anchors, hidden translations, semantic conservation and exact second-projection rules unchanged. A final projection mismatch or incompatible mandatory lead remains a refusal, not permission to grow sizes or iterate.
Two useful simplifications: source-center ordering does not require target-ancestor-before-descendant execution, since a target ancestor's translation does not change the order of consumed external source values. Explicit source-influence dependencies plus absolute coordinate recomposition are sufficient. Also, arbitrary intermediate geometry within a dependency SCC need never be externally visible: compute its decisions before committing any of them.
## Important limits and traps
**Ordinal slots are not fixed Y coordinates.** If an 80-high and 200-high block trade old Y coordinates, they can overlap. Preserve ordinal indices, then recalculate packed Y values using the unchanged heights. The layer envelope is nevertheless unchanged: height is the same sum of heights plus gaps, and width is the same maximum. Every ancestor enclosure is consequently unchanged by induction, even for nested containers. Nested size feedback is not inherent in this permutation stage.
**Automatic port projection remains geometry dependent.** Rearrangement may select different automatic sides or put more ports onto a side, increasing projected size beyond the frozen plan. Derived enclosure invariance does not exclude that. The exact final projection and lead checks must catch it. Preserve explicit port-side and fraction metadata. A center-based score may worsen actual fixed-port endpoint order; inspect routed outcomes and include that counterexample in evaluation.
**Determinism differs from idempotence.** Complete canonical reconstruction plus deterministic dependency processing gives same-input determinism. It does not prove repeated-call equality because the next input's effective minima may include stored enclosure repairs or new side-capacity minima. Existing repeated-call checks must remain, including nested automatic-port cases, and must compare complete Projects. Do not justify a failed repeat by saying that the ordering graph is deterministic.
**Canonical choice is a policy, not evidence of quality.** Alias and placement-ID keys are defensible tie breakers already present in this experiment. They imply sensitivity to alias changes and duplicate-alias placement IDs. Relation-ID permutation should not change geometry or scores. Full graph-isomorphism invariance is neither supplied by the current planner nor established by this proposal. Diagnostics should distinguish a canonical tie from a strict source-derived ordering decision.
**Cyclic dependency SCCs have no guaranteed winner.** Simultaneous calculation is independent of group traversal order, but opposing permutations may both reverse and remain crossed. Freezing canonical order for cyclic SCCs is a still more conservative alternative if the corpus shows worsening; predeclare which policy is being tested. Do not quietly select between the two after routing each fixture. Sequential execution within a cyclic SCC merely chooses an arbitrary winner and is not a resolution of the constraints.
**Non-singleton target blocks weaken the center proxy.** Two SCCs can receive edges into different perimeter rows. Mean external-source center ignores target member offsets, so it can place their block centers in an order that crosses the actual connections. An offset-adjusted score would be a different candidate and would introduce dependencies on target descendants as well. Keep this limitation explicit and use a cyclic-block target fixture; do not add that refinement without a separate reason and specification.
**External order can conflict with internal rank order.** The current canonical pass already uses preceding-rank proximity. Overriding its same-rank order from boundary neighbors can increase internal crossings. A fixture must include this conflict, and evaluation must retain all internal and external routes. Success on one reversed-child witness is insufficient.
## Falsifying fixtures and acceptance evidence
- Preserve the frozen 14 cases and exact complete sparse candidate geometry/metrics. The targeted two-container witness should reach zero shared length and zero label/node collisions like old layered, without semantic, port, fold or import regression; report the whole quality vector rather than only that target.
- Three containers A→B→C, two matched channels, chosen aliases giving differing canonical child orders. A second version with a longer chain distinguishes an actual dependency sweep from a fixed snapshot-pass count. Verify final channel alignment and dependency order from emitted plans, not just zero process exit.
- Ancestor influence: an ordering group moves a container holding an external source whose own immediate child group does not reorder; that source feeds a different target group. The target must consume the source's updated absolute Y. Reverse container IDs to expose accidental iteration dependencies.
- Opposing incoming constraints between two containers; a three-container directed cycle; and an acyclic semantic graph whose container grouping induces a dependency cycle. Confirm the declared cyclic policy and same-input determinism, and report unresolved crossings rather than claiming all cycles solved.
- Heterogeneous block heights with an unanchored block between two anchored blocks. Require unanchored ordinal-slot preservation, no overlap, exact unchanged total envelope and deterministic packing. Repeat with nested containers and a multirow SCC.
- A same-rank chain of undirected-connected blocks plus externally anchored endpoints, and a purely undirected cross-container fixture. Require the declared bundle/freeze policy, no invented directed arcs/ranks and no silent loss of existing contiguity.
- An internal diamond or fan-out whose canonical target order is good but boundary signals prefer its reverse. Detect improvement to the boundary at the cost of internal tracing.
- Fixed ports with source-center order opposite to port-attachment Y order; many automatic ports near a side-choice/capacity threshold. Require exact model-anchor preservation and final projection acceptance or clean refusal, never size chasing.
- A collapsed source container promoting hidden edges; nested collapsed descendants; and a surviving dormant authored route. Require only visible geometry to influence ordering, hidden translation with owner, and the existing route/reset conservation contract.
- Parallel boundary relations and a relation-ID permutation with identical endpoints; equal mean scores; repeated invocation; JSON/text round trips. Require exact geometry determinism under relation-ID changes and exact repeated Projects. Route relation-ID sensitivity remains a separate existing router limitation.
The existing full corpus remains the primary comparative experiment. These small synthetic fixtures test the candidate's mechanism and claimed invariants. No compilation result, small-corpus metric or this design review establishes native usability, production Arrange integration, or release acceptance.
## Final selected-policy review
The parent's final proposal adopts indivisible undirected-connected bundles, deduplicated visible source owners, active groups only when some band has at least two anchored units, source-ancestor dependencies only, and one simultaneous pre-SCC snapshot for each cyclic dependency SCC. I find no material correctness flaw in that bounded contract, provided the following definitions are implemented literally:
- A source owner is the projected edge's visible source **placement ID**, not a semantic element ID or unprojected port owner. Distinct visible placements remain distinct observations; promoted endpoints contribute their visible owner.
- The source influence chain includes the ordering group immediately containing the source placement, and every higher active ordering group that can move it. It must not start one level too high.
- Bundle order is preserved by ordinal slot, then prefix-height packing; old absolute Y coordinates are not reused for differently sized blocks.
- Before an SCC computes scores, all source absolute coordinates are recomposed from the current full offset map. All its proposals are calculated before any are committed.
- Work charging and diagnostic bounds include ancestor-chain discovery, dependency SCC processing, source-set accumulation and absolute-coordinate recomposition.
Active-group restriction is sound for this contract: fewer than two anchored units cannot change order because unanchored unit slots are preserved. Unchanged active groups can conservatively remain dependencies. No extra hierarchy edges are necessary.
The important remaining risks are empirical: cyclic dependencies may preserve or exchange crossings, source-center order can disagree with fixed-port/perimeter attachment order, deduplicated owners intentionally ignore connection multiplicity, and boundary preference can worsen internal rank tracing. Keep those limitations and the chain/ancestor influence fixtures above. Exact repeated-call stability and final automatic-port projection remain acceptance checks, not consequences of the ordering proof.
@@ -1,46 +0,0 @@
# Independent boundary-order evaluator contract
Source inspection at research f4fa0c11; controls are frozen SCC run02 and prior old-layered results. No implementation, compiler, router, UI or Gitea action. Evaluate one predeclared boundary-order candidate, not a family selected after viewing scores.
## Exact missing information
`layered.rs` incoming-neighbor pass (approximately137–167) considers an edge whose target lifts to the current child and whose source does not lift to that same child. An external source need not be a sibling. Its world-space center Y influences downstream child order. Three passes carry updated positions between groups; outgoing neighbors are intentionally not chased simultaneously, avoiding a swap of both groups that preserves reversal. This is a useful mechanism, not a proof that its three-pass update converges for arbitrary parent cycles.
`condensed.rs:224–241` requires BOTH endpoints to lift into the same sibling group before retaining a link. Thus an external source contributes no local child-order information. Lines365–390 only order SCC blocks from lower-ranked neighbors already in that local links list, followed by same-rank proximity. Correct root condensation knows Left→Right, but the singleton children inside Right have neither local arcs nor external order hints. Their component/canonical order survives. This omission is separate from the successfully fixed SCC rank problem.
## Existing two-container witness: fixed expected order
Fixture definitions are `auto_layout_probe.rs:580–603`. Placement suffixes uniquely identify this fixture:
- Left parent002: Left A006 then Left B008.
- Right parent004: Right A00a then Right B00c.
- Directed edge00d: Left A006→Right B00c.
- Directed edge010: Left B008→Right A00a.
In frozen SCC run02 both groups retain A above B: child Y136 and300. The concrete downstream order witness is **Left A < Left B and Right B < Right A** (compare projected centerY; names are labels, IDs are identities). Preserve Left's order as the upstream reference; swapping both groups is not success. The mirrored physical arrangement can be equivalent globally, but it is not the predeclared one-sided witness. Every child remains under its original parent and each parent's local SCC membership/rank remains unchanged.
Old layered establishes a feasible target with unchanged semantic endpoints: zero shared length/contacts/label collisions versus SCC164 sharing,2contacts,1label/node; route length372 versus788, area272800 versus339852. Do not assert the new implementation must reproduce every coordinate. Require the ordered pairs above and compare actual final released routes to that zero-sharing witness. Smaller connector inversions alone do not pass if routing still merges the traces or labels become obstructed.
## Three additional topology falsifiers, fixed before implementation
Use equal-size ordinary SA function children, no authored ports initially; add explicit anchors only as the stated separate invariant variant. Stable aliases A/B determine the unconstrained upstream order. Use the same renderer-independent node sizes/gaps as existing fixtures, not dimensions chosen after candidate output.
1. **Opposing cross-parent evidence.** Two parents L/R, children A/B each; arcs L.A→R.B, L.B→R.A, R.A→L.A, R.B→L.B. The first pair asks for opposite L/R order; the second pair asks for matching order. These demands are incompatible. Expected: semantic direction and SCC condensation remain exact, deterministic bounded resolution with explicit ties/diagnostics, no endless joint swapping or silently dropped arcs. Do NOT require zero crossing or a particular arbitrary winner. Repeated full candidate calls must stabilize; route/label costs and any introduced hard violation remain visible.
2. **Three-parent propagation.** Parents L/M/R with A/B children. Arcs L.A→M.B, L.B→M.A, M.B→R.A, M.A→R.B. With upstream L.A<L.B fixed, expected M.B<M.A and R.A<R.B. This catches a one-step only pass and averaging stale absolute coordinates from differently positioned parents. Add no reverse arcs. Verify final relative child orders and actual connection quality; parent ranks must remain L<M<R. Run a storage/relation-ID permutation without changing semantic topology and report any different order explicitly.
3. **Multiple SCCs and local ranks.** Within target parent T, two two-member directed SCCs X=(X1↔X2) and Y=(Y1↔Y2), each feeds singleton Z via X2→Z and Y2→Z. External parent S has upperA/lowerB, with S.A→Y1 and S.B→X1. Expected same-rank block Y above X, both before Z's rank; preserve exact SCC membership and internal perimeter order. This catches implementations that sort all children globally by external neighbor Y, split cyclic blocks, or move Z into the same rank. Boundary ordering must act on SCC blocks within an existing rank, not override rank constraints. If cross-boundary preference is unsupported for multi-member blocks, return/report that scope explicitly rather than falsely claiming this fixture passes.
These are structural tests, not new gap or penalty parameters. One variant of the main witness should retain authored port-side/offset anchors to ensure order is achieved by permissible geometry, not anchor mutation. Undirected edges supply no invented rank direction; reversing their stored endpoint order must not change their meaning or create hidden directed precedence. Preserve the existing compound/folded corpus instead of constructing a grand taxonomy of synthetic cases.
## Acceptance checks for the single candidate
Retain all14 existing cases with full failures, reset/old-layered/SCC controls and raw before/after Projects. Require exact source/model conservation under declared node geometry plus existing route reset/translation; original semantic orientation, containment, port identities, attachments and route-entry ordering remain exact. Parent owns the complete Project oracle. Folded nodes remain opaque; stored expanded sizes and latent descendant offsets survive fold→layout→expand, and out-of-projection placements are untouched according to the existing contract.
Independently reconstruct quotient SCC membership, condensation ranks and rank membership before comparing boundary orders. Record hints with edge identity, actual external owner and destination block, using final projected coordinates or a deterministic canonical order as explicitly specified; avoid alias-only success claims. If ordering is ordinal, compare like-for-like coordinates within a reference parent rather than treating arbitrary parent Y translation as semantic priority. Parallel edges must not be silently deduplicated or weighted accidentally by whichever container pass saw them first.
Final actual projection is authoritative for automatic port sides/positions, node capacity and enclosure. Require exact authored anchors, no hard lead incompatibility, no new unrelated node/header penetration or overlap, and preserved pin/metadata policy. Report final route crossings, proper/T/bend contacts, raw/edge-deduplicated sharing with identified pairs, labels, area and length. Keep folded retrace visible. A better topological order that worsens actual traceability is not accepted automatically.
**Sparse40 exactness is a predeclared preservation target**: it is flat and lacks cross-parent boundary relations, so its whole candidate Project, plan geometry and metrics should remain exact to run02 (except new diagnostic fields). Prefer the same check for every case without applicable cross-boundary hints. If it changes, demand a causal explanation and classify it as scope leakage rather than accepting an accidental improvement. Mixed and reversed-ID cases are also flat: preserve their existing outputs, including known differences, rather than promising to remove router ID sensitivity in this change.
Require same-input determinism and ten full repeated candidate calls, including opposing parents, multilevel propagation and the real folded/compound views. Success cannot depend on starting from the special fixture's authored Y values alone; compare a harmless uniform translation of an entire parent subtree while preserving local child order. With canonical ordering policy, this should not reverse the result merely by changing the parent's global position. An explicitly geometry-sensitive policy must state that tradeoff before testing.
Stop after one implementation and one frozen comparison. A viable result must solve the exact existing two-container order/tracing witness, preserve sparse/mixed flat outputs, survive the contradictory/chained/multi-SCC tests without topology corruption or instability, and retain all real-case regressions transparently. Production command/history integration and native tracing remain separate acceptance work; passing these geometry checks alone is not closure of #32.
@@ -1,791 +0,0 @@
{
"schema": 1,
"source_commit": "3e21c1bca245944ae0ec7bb02aaa920f45f2cc30",
"archive": {
"file": "boundary-order-3e21c1bc.zip",
"bytes": 4310136,
"sha256": "bb6b896ff2401290869a904f7768ebb52b6f0ab36fada06badbe9abb301c37b8"
},
"members": [
{
"member": "collector/archive-boundary-order-20260925.py",
"bytes": 3843,
"sha256": "81adb0add2c57a4c1109efc8b74ba0f6ffb37250abc8edcd95b30853a93eebab"
},
{
"member": "collector/audit-boundary-conservation-20260925.py",
"bytes": 17232,
"sha256": "f14d96f7ee1487d245bd30436dea356df7524006c51f2fbac929b067b881d893"
},
{
"member": "collector/audit-boundary-order-20260925.py",
"bytes": 5352,
"sha256": "96bb938961255b59add3922f2cc8b30ddc7ec127d77ab1d7b61974e116930432"
},
{
"member": "collector/audit-scc-placement-v3-20260925.py",
"bytes": 8729,
"sha256": "8b238f010eeb81720a59a0ad290544f87934acb8070e58a3fd25f9eda9f47a0d"
},
{
"member": "collector/launch-boundary-native-20260925.py",
"bytes": 13468,
"sha256": "4d75605389ee53a6a2d2b73b7fd9c28400db89efce1097c7fad5656e7bf4d663"
},
{
"member": "collector/run-boundary-order-20260925.py",
"bytes": 4575,
"sha256": "01c6ddd4953ee485123cbed5d99aa4f1b485b21be69083828959cf50c938a9b1"
},
{
"member": "collector/run-routing-corpus-check-20260925.py",
"bytes": 2793,
"sha256": "2726a397bd4ecb4dcfff6fc170a66ce2655229079f42335faa2a4bfe4a202f6d"
},
{
"member": "gates/27-boundary-example-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/27-boundary-example-tests/command/context.json",
"bytes": 3510,
"sha256": "13b6e4d82cd228eabe26a45c3294fef319eccd8edca784f5b41d3de7003b65ec"
},
{
"member": "gates/27-boundary-example-tests/command/inputs-after.json",
"bytes": 1762589,
"sha256": "800940ce4e0bd2b3bd56b87f65308808dc99e5f897d643bffa04405de211bfbd"
},
{
"member": "gates/27-boundary-example-tests/command/inputs-before.json",
"bytes": 1762589,
"sha256": "800940ce4e0bd2b3bd56b87f65308808dc99e5f897d643bffa04405de211bfbd"
},
{
"member": "gates/27-boundary-example-tests/command/output.log",
"bytes": 1385,
"sha256": "a2e29cb282440949664ca33aafc6c0174c6394a2327e76ad16994aa3ee21b3b7"
},
{
"member": "gates/27-boundary-example-tests/command/result.json",
"bytes": 4184,
"sha256": "ccc581072ecdd59c8b9881571aae6aaf32c4eb6ccbbcc7d712e9ef2cec9655ac"
},
{
"member": "gates/27-boundary-example-tests/command/stderr.log",
"bytes": 336,
"sha256": "b3f2054556656f6a805f054ffb8d5c780be84b69c65135cc6c0d28f7d1a7d6f8"
},
{
"member": "gates/27-boundary-example-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/27-boundary-example-tests/orchestration.log",
"bytes": 185,
"sha256": "6f08f77e5593cbd746ee6ab7b6f16641bee0a7058f03b9e2fb04b7cb747c8181"
},
{
"member": "gates/28-boundary-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/28-boundary-clippy/command/context.json",
"bytes": 3540,
"sha256": "b1686a8cfac3bfec3627da11f0950826c2a06dcb115851723ac1987b8ca91c3d"
},
{
"member": "gates/28-boundary-clippy/command/inputs-after.json",
"bytes": 1762589,
"sha256": "800940ce4e0bd2b3bd56b87f65308808dc99e5f897d643bffa04405de211bfbd"
},
{
"member": "gates/28-boundary-clippy/command/inputs-before.json",
"bytes": 1762589,
"sha256": "800940ce4e0bd2b3bd56b87f65308808dc99e5f897d643bffa04405de211bfbd"
},
{
"member": "gates/28-boundary-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/28-boundary-clippy/command/result.json",
"bytes": 4197,
"sha256": "2fbd9f68cc45957b62122fda4b022a9e6eb3661a871132f06444f87ef862c9bf"
},
{
"member": "gates/28-boundary-clippy/command/stderr.log",
"bytes": 176,
"sha256": "7be90bc986d32ae1b1f4bf7e877bbcb73389e60288af76e6af2b6626e8cd2626"
},
{
"member": "gates/28-boundary-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/28-boundary-clippy/orchestration.log",
"bytes": 178,
"sha256": "ce952a08d4fe80b4e7091db3ec33ab562136997a9c6900c3efde32bbf027793f"
},
{
"member": "gates/29-boundary-precision-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/29-boundary-precision-tests/command/context.json",
"bytes": 3512,
"sha256": "df7d084938c7f45b6b4d7229124ad92eeb4dcbde80d77cfac6a1902754d72f9a"
},
{
"member": "gates/29-boundary-precision-tests/command/inputs-after.json",
"bytes": 1762589,
"sha256": "8c1c5b141d9322956c9914284387fd1471879a0cfadd4eb720e1be3cdbcd524e"
},
{
"member": "gates/29-boundary-precision-tests/command/inputs-before.json",
"bytes": 1762589,
"sha256": "8c1c5b141d9322956c9914284387fd1471879a0cfadd4eb720e1be3cdbcd524e"
},
{
"member": "gates/29-boundary-precision-tests/command/output.log",
"bytes": 1473,
"sha256": "bf6344286c5fb4531117b25deef585502167c9ffaf7f11416bd7b9af9fde2659"
},
{
"member": "gates/29-boundary-precision-tests/command/result.json",
"bytes": 4190,
"sha256": "5a412dc08cb74c2bb2206b901e97878b29a1a87f7c26891981b08db374a20fe2"
},
{
"member": "gates/29-boundary-precision-tests/command/stderr.log",
"bytes": 336,
"sha256": "e4f89d4438ee4f29fdd9c827af6c8b9c6be621182e734b094ffedbcd3d03a467"
},
{
"member": "gates/29-boundary-precision-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/29-boundary-precision-tests/orchestration.log",
"bytes": 187,
"sha256": "205746a7fd277265ba7f1a3c52073fdc9618909dfab31b9f15ff210abf4abbed"
},
{
"member": "gates/30-boundary-precision-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/30-boundary-precision-clippy/command/context.json",
"bytes": 3550,
"sha256": "fe1ce5ca19ef4c19b1c4627c73ef3d42c4be20da52952de5fe0ebf606e549d6c"
},
{
"member": "gates/30-boundary-precision-clippy/command/inputs-after.json",
"bytes": 1762589,
"sha256": "8c1c5b141d9322956c9914284387fd1471879a0cfadd4eb720e1be3cdbcd524e"
},
{
"member": "gates/30-boundary-precision-clippy/command/inputs-before.json",
"bytes": 1762589,
"sha256": "8c1c5b141d9322956c9914284387fd1471879a0cfadd4eb720e1be3cdbcd524e"
},
{
"member": "gates/30-boundary-precision-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/30-boundary-precision-clippy/command/result.json",
"bytes": 4227,
"sha256": "df153dbc6cfa994be50f3ade29023885397131d4b66727e5464781acd473b339"
},
{
"member": "gates/30-boundary-precision-clippy/command/stderr.log",
"bytes": 176,
"sha256": "971c0f30a7e4473172912bf8e3d34edd27c36a6df689613be3bac74262dc89b7"
},
{
"member": "gates/30-boundary-precision-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/30-boundary-precision-clippy/orchestration.log",
"bytes": 188,
"sha256": "2aa50a7d9dfa26b6281a5492584836edf59ad7fab5ece9e1ade8df5c618690b0"
},
{
"member": "gates/31-boundary-release/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/31-boundary-release/command/context.json",
"bytes": 3529,
"sha256": "8d95ec8851bdb5298456db6779c3935c992ac94fb01006b5bda77733f035643d"
},
{
"member": "gates/31-boundary-release/command/inputs-after.json",
"bytes": 1762589,
"sha256": "8c1c5b141d9322956c9914284387fd1471879a0cfadd4eb720e1be3cdbcd524e"
},
{
"member": "gates/31-boundary-release/command/inputs-before.json",
"bytes": 1762589,
"sha256": "8c1c5b141d9322956c9914284387fd1471879a0cfadd4eb720e1be3cdbcd524e"
},
{
"member": "gates/31-boundary-release/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/31-boundary-release/command/result.json",
"bytes": 4188,
"sha256": "c9eb4f6148e4dc81bf03225600b67608044ebd9c2a2e5fff8cfa1a6fcedad526"
},
{
"member": "gates/31-boundary-release/command/stderr.log",
"bytes": 179,
"sha256": "cb88f4b7def4df8a09d67f7fdff2046fb076a0ea293f525cae46a59f801bf019"
},
{
"member": "gates/31-boundary-release/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"member": "gates/31-boundary-release/orchestration.log",
"bytes": 179,
"sha256": "577b9b108998d0e065a53dc08f658cb42026a539fe4b692bc5d50a44da49eca1"
},
{
"member": "inputs/corpus/manifest.json",
"bytes": 10593,
"sha256": "a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717"
},
{
"member": "inputs/corpus/mixed_dispatch.json",
"bytes": 32787,
"sha256": "81d25af021cbad18af4262a220ba60372e51ca19083b7e80f2b19196baf05990"
},
{
"member": "inputs/corpus/mixed_dispatch_edge_ids_reversed.json",
"bytes": 32787,
"sha256": "25c95be6b6e7ad9ebcdc83aacc13fbbaa5a56651ba2843f8d1658c075ed789f8"
},
{
"member": "inputs/corpus/subsystems_40_sparse.json",
"bytes": 124043,
"sha256": "ad0ee7a0ab9c9f3c5f26a6d839f6627a82aa38858a3d5cc1ca87f5a8d795533e"
},
{
"member": "inputs/corpus/workshop_sa_folded.json",
"bytes": 102922,
"sha256": "ea5fd285d11795e5e543e4144349c32c92a5b328b8c5e2d1be8b75b70703dc97"
},
{
"member": "inputs/corpus/workshop_sa_original.json",
"bytes": 102923,
"sha256": "cc9b26390594513c11b3d85b768d244b2df8e7bed8cb76c4bdf0dc24db1d2ef6"
},
{
"member": "inputs/prior-arrange-controls.jsonl",
"bytes": 1862455,
"sha256": "f924af4038ade0de2e0f44988fa28d2566019d8c4bc2bde70e61fe4813364d40"
},
{
"member": "inputs/released-route-control.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "inputs/scc-run02/mixed_dispatch/stdout.jsonl",
"bytes": 93898,
"sha256": "28a7f598746f4c0c58afd0321861e417b2715976cde52bf55361dce8c35b4d74"
},
{
"member": "inputs/scc-run02/mixed_dispatch_edge_ids_reversed/stdout.jsonl",
"bytes": 93308,
"sha256": "6a723a4899026c2df80327fb76c5dda8e5dc5e4e15e9e066991413c2246bade5"
},
{
"member": "inputs/scc-run02/route-control/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "inputs/scc-run02/small-controls/stdout.jsonl",
"bytes": 425661,
"sha256": "0ec2bc1f51542b41b5df0b89d2a87306716a49a22951c4dfeb128dd75247d074"
},
{
"member": "inputs/scc-run02/small-scc/stdout.jsonl",
"bytes": 220188,
"sha256": "0c8b9ef7888cd5ba99733f15d22478cdb2878ef02e22d297d02c8b3eea2e9e15"
},
{
"member": "inputs/scc-run02/subsystems_40_sparse/stdout.jsonl",
"bytes": 361147,
"sha256": "452690f23dda57f62d115b6d88e42d7f0283b4c86081d5149d8738ba6052e53b"
},
{
"member": "inputs/scc-run02/workshop_sa_folded/stdout.jsonl",
"bytes": 194613,
"sha256": "ddf05a2ca36950305090bd5d91ec2a6c617d2eae373c33ad84e9ff4157581c0c"
},
{
"member": "inputs/scc-run02/workshop_sa_original/stdout.jsonl",
"bytes": 198272,
"sha256": "e30a2a6a30d1522cb2f8e9377e7eb8f0a81d1fe8b5aa18550f78c4829b8cc408"
},
{
"member": "native/inputs/boundary_two_containers_anchored__boundary.json",
"bytes": 8997,
"sha256": "f84fafbc3a80aee5caebf5b1cd6d41f340d954342664c64e7b627ba4fcefbe39"
},
{
"member": "native/inputs/boundary_two_containers_anchored__scc.json",
"bytes": 8997,
"sha256": "1da4878fa52fe665e4639eb1a9cc99b5b0e85516dd51f898270ed619c4eafb06"
},
{
"member": "native/inputs/boundary_two_local_sccs__boundary.json",
"bytes": 16991,
"sha256": "c408c437d60a8f62952151d1880ea50bc10985d5ffadec1d91b25361c1862737"
},
{
"member": "native/inputs/boundary_two_local_sccs__scc.json",
"bytes": 16991,
"sha256": "a6e83c92dd4b9a4cb59054730b81a995a4ed2351d9a865e0c7a1572a80542dc0"
},
{
"member": "native/inputs/two_containers_reversed_children__boundary.json",
"bytes": 8179,
"sha256": "6ed26cc72a540207f31c04bd989dfa718b1c573be1d15fcffebc8046c32fb84f"
},
{
"member": "native/inputs/two_containers_reversed_children__scc.json",
"bytes": 8179,
"sha256": "56e980ef38cdc24e1a6b710557736c84026bb052da7e88726d55fd61e5d0c375"
},
{
"member": "native/manifest.json",
"bytes": 7509,
"sha256": "940a7605b5a83308261e1fde0ecd7291cc855614a515e87e084823c8fc4e9016"
},
{
"member": "native/observations/01-two-container-boundary.json",
"bytes": 294,
"sha256": "aa930a00b846e037130a219043d0e71892be95ce3c3739ccb2b88956d4d204af"
},
{
"member": "native/observations/01-two-container-boundary.png",
"bytes": 122265,
"sha256": "bc4e28a0fcc37cdc4c904993b67e5b018c66a3a0a2ff7c2511fec324e03d5cd7"
},
{
"member": "native/observations/02-two-container-scc.json",
"bytes": 310,
"sha256": "741b04f292bdfea132a8131525be0f6215fa4d557100dd8114e41cb2e3088dbf"
},
{
"member": "native/observations/02-two-container-scc.png",
"bytes": 122550,
"sha256": "e1c68d66a4eae12c2e2c056858a1d4fc6b5eec8c387ee39b19337abbce7f49cf"
},
{
"member": "native/observations/03-anchored-boundary.json",
"bytes": 310,
"sha256": "e175e1ed5c9ae6a551bad7f6fd16badabeff245e0fe5c37876421467ce4b70eb"
},
{
"member": "native/observations/03-anchored-boundary.png",
"bytes": 122077,
"sha256": "8038656c660d826426c36e059997eb955ef8e84db4bdc2d23bcc214f64580c1d"
},
{
"member": "native/observations/04-local-scc-boundary.json",
"bytes": 310,
"sha256": "81f0bb6e233b37c5c119c6b0c158abb18bb2632af172136cc7411289a14f4865"
},
{
"member": "native/observations/04-local-scc-boundary.png",
"bytes": 120833,
"sha256": "677057c6870103daeeb31d48a11a5f9b8b8ebb604a7864e71a541a28d6024342"
},
{
"member": "native/observations/05-local-scc-selected-lower-boundary.json",
"bytes": 301,
"sha256": "e2ba43b96ffef6f6c6b4a349456d428a1f6b65d329cae7a0cf8fee6e0cec4d26"
},
{
"member": "native/observations/05-local-scc-selected-lower-boundary.png",
"bytes": 132475,
"sha256": "732cc188a8e8fbe3632d3bd824f218560c5a40afac053d5f8936e62be2699861"
},
{
"member": "native/run01/close.json",
"bytes": 3845,
"sha256": "a89d86f5c321299b034d1b5b28a635ee0574736d9ef715ba1c85fd26fc0fde1c"
},
{
"member": "native/run01/preflight.json",
"bytes": 3503,
"sha256": "1aa792b64b96fee428594d76f4c838256db7e4d86ef12f12cfc59e197ff96178"
},
{
"member": "native/run01/profile/ArcadiaStudio/recent-models.json",
"bytes": 946,
"sha256": "cfa44a8c46c193ba27b41ad84ba437a588250b4bed27437dfb4c2a1cb08b8f8b"
},
{
"member": "native/run01/start.json",
"bytes": 453,
"sha256": "5e403aff77fc582f961fad424bbd863ebcd2c069d939963ea2723ccee6f63dd1"
},
{
"member": "native/run01/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "native/run01/stdout.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "native/run01/working/boundary_two_containers_anchored__boundary.json",
"bytes": 8997,
"sha256": "f84fafbc3a80aee5caebf5b1cd6d41f340d954342664c64e7b627ba4fcefbe39"
},
{
"member": "native/run01/working/boundary_two_containers_anchored__scc.json",
"bytes": 8997,
"sha256": "1da4878fa52fe665e4639eb1a9cc99b5b0e85516dd51f898270ed619c4eafb06"
},
{
"member": "native/run01/working/boundary_two_local_sccs__boundary.json",
"bytes": 16991,
"sha256": "c408c437d60a8f62952151d1880ea50bc10985d5ffadec1d91b25361c1862737"
},
{
"member": "native/run01/working/boundary_two_local_sccs__scc.json",
"bytes": 16991,
"sha256": "a6e83c92dd4b9a4cb59054730b81a995a4ed2351d9a865e0c7a1572a80542dc0"
},
{
"member": "native/run01/working/two_containers_reversed_children__boundary.json",
"bytes": 8179,
"sha256": "6ed26cc72a540207f31c04bd989dfa718b1c573be1d15fcffebc8046c32fb84f"
},
{
"member": "native/run01/working/two_containers_reversed_children__scc.json",
"bytes": 8179,
"sha256": "56e980ef38cdc24e1a6b710557736c84026bb052da7e88726d55fd61e5d0c375"
},
{
"member": "native/staging.json",
"bytes": 331,
"sha256": "df221a4389c519db81276595d8154661da78812798af64b49e81c382ecaae348"
},
{
"member": "reviews/boundary-conservation-audit-20260925.json",
"bytes": 221331,
"sha256": "a59a3dcdd72eeab1502570d5189a31b2560bed57ed0d4f072a41e6de1534ac0e"
},
{
"member": "reviews/boundary-conservation-audit-final-20260925.json",
"bytes": 235597,
"sha256": "f6a3fa93c03174e0eae6f816975f06a10a696659bd3fd58291ac805a69d5edee"
},
{
"member": "reviews/boundary-conservation-review-20260925.md",
"bytes": 4315,
"sha256": "2612286fb2696f0276615427b303f3fd348098e59a00ae4f4683b04e812fd7d1"
},
{
"member": "reviews/boundary-native-observation-20260925.md",
"bytes": 2698,
"sha256": "fccd79467f48a0593256c9858ac14609a9291f3271c491f8149739314667cd48"
},
{
"member": "reviews/boundary-native-review-20260925.md",
"bytes": 6850,
"sha256": "e791925f8794e10c966f4e45d5bfb560395873d2dd2b0258340087ef20ba67a2"
},
{
"member": "reviews/boundary-order-design-critique-20260925.md",
"bytes": 17016,
"sha256": "100147aa35aff59840563e8c5c37a7c56298671910e805f55c21cac0373f435f"
},
{
"member": "reviews/boundary-order-evaluation-20260925.md",
"bytes": 8964,
"sha256": "bfdb122e9fdb5532137e5760381d7a61ef094d203ab2e3b157f90c0674894e0b"
},
{
"member": "reviews/boundary-order-implementation-20260925.md",
"bytes": 4464,
"sha256": "31e1657cc05aff9b0a802b84786baf478b3ba8913f3c241e585f24a47875c9ba"
},
{
"member": "reviews/boundary-order-independent-audit-20260925.json",
"bytes": 158196,
"sha256": "914e39cf9297ab025927b9ba9bae02adee157e3dc7061058e67ee280cb6cb212"
},
{
"member": "reviews/boundary-order-result-review-20260925.md",
"bytes": 7224,
"sha256": "b9cc9692c094d35f88f71f43b035d08d375e4350c88bad35ee07420c10bfb9e9"
},
{
"member": "reviews/boundary-order-source-review-20260925.md",
"bytes": 9618,
"sha256": "21eb621bca634a8ab0fbc122092a3c41281d121078b40651bf66eae7f6556165"
},
{
"member": "run01/boundary-extra/receipt.json",
"bytes": 903,
"sha256": "12c11a00ed7931e77034ad69ef35b2f53ea08960ff836c9bd2605b632fc4673b"
},
{
"member": "run01/boundary-extra/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/boundary-extra/stdout.jsonl",
"bytes": 488611,
"sha256": "5695e09f332a2876592134a4b0621e6a6c22b03ab5dbee6d21393a48e3e2d99b"
},
{
"member": "run01/boundary-small/receipt.json",
"bytes": 897,
"sha256": "78dce798e743b1a3547ba81ec8c86644d1a99b8e5f46ff6640db6151a426ad4f"
},
{
"member": "run01/boundary-small/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/boundary-small/stdout.jsonl",
"bytes": 222634,
"sha256": "fadde557248cdf0cbef1a127683f7fb2244608e9940a385b490caf242ab93ed2"
},
{
"member": "run01/capture.json",
"bytes": 5928,
"sha256": "7346d81f31a09ea660121deaee25215829d7d559a6e08f762394500c36a4ced4"
},
{
"member": "run01/mixed_dispatch-scc-control/receipt.json",
"bytes": 1140,
"sha256": "43eb6ce30ee2f9efd27da2b0366618c44e6630f93d2162fdb217b6d2e41088e5"
},
{
"member": "run01/mixed_dispatch-scc-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch-scc-control/stdout.jsonl",
"bytes": 93898,
"sha256": "28a7f598746f4c0c58afd0321861e417b2715976cde52bf55361dce8c35b4d74"
},
{
"member": "run01/mixed_dispatch/receipt.json",
"bytes": 1108,
"sha256": "b18abee69afd6097a54bad381fc56e6e7f842efb7130043b1af4656af11d1e8d"
},
{
"member": "run01/mixed_dispatch/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch/stdout.jsonl",
"bytes": 94148,
"sha256": "ac99f7222fbabdf19cdd9fd64d77251a8bd66f2cc54f285415ffae655df574cb"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-scc-control/receipt.json",
"bytes": 1212,
"sha256": "6739ca9bc76cf7deed0579e74ab784453bce0c2a223cae3e3e041d0e9a5c4b6a"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-scc-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-scc-control/stdout.jsonl",
"bytes": 93308,
"sha256": "6a723a4899026c2df80327fb76c5dda8e5dc5e4e15e9e066991413c2246bade5"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed/receipt.json",
"bytes": 1181,
"sha256": "e20402a551f8b1a0e3bb37880aba6efbeee935f7e33b07e0c2c30852c66873dd"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed/stdout.jsonl",
"bytes": 93558,
"sha256": "2c6fc18cc10edf82b67db666ebbf5a143f3f0090558cb37e6d941c23b5aa49b3"
},
{
"member": "run01/receipt.json",
"bytes": 28320,
"sha256": "9aeaeedd81d968d353c48fc32126c7644c452e3b0679ac67ab4fbad7f985ba49"
},
{
"member": "run01/route-control/receipt.json",
"bytes": 1050,
"sha256": "3bbd687895501ef451d51c300ce084eb0368bd8ecb3fff3de58573c9187cedff"
},
{
"member": "run01/route-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/route-control/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "run01/scc-small-control/receipt.json",
"bytes": 900,
"sha256": "138fc549ae60641c5eb9fd77b9ca379e2ffb42d21fc365ccdbc967803cdeb44a"
},
{
"member": "run01/scc-small-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/scc-small-control/stdout.jsonl",
"bytes": 220188,
"sha256": "0c8b9ef7888cd5ba99733f15d22478cdb2878ef02e22d297d02c8b3eea2e9e15"
},
{
"member": "run01/small-controls/receipt.json",
"bytes": 868,
"sha256": "475254bd941a3a39296c1b251a1d90f0a540b49d652c9c40ee7a928412439af3"
},
{
"member": "run01/small-controls/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/small-controls/stdout.jsonl",
"bytes": 425661,
"sha256": "0ec2bc1f51542b41b5df0b89d2a87306716a49a22951c4dfeb128dd75247d074"
},
{
"member": "run01/subsystems_40_sparse-scc-control/receipt.json",
"bytes": 1165,
"sha256": "181eb29b33c4b976dddedf12f9527fa2ae1381e588c7af620ad88d5ee47b1706"
},
{
"member": "run01/subsystems_40_sparse-scc-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse-scc-control/stdout.jsonl",
"bytes": 361147,
"sha256": "452690f23dda57f62d115b6d88e42d7f0283b4c86081d5149d8738ba6052e53b"
},
{
"member": "run01/subsystems_40_sparse/receipt.json",
"bytes": 1134,
"sha256": "6ed2ca8414aa4bb56c3c34a2af7832b844c51cc89e74834bc8800dcb92cdd7ba"
},
{
"member": "run01/subsystems_40_sparse/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse/stdout.jsonl",
"bytes": 361397,
"sha256": "26925d461fb34af1a728912d143d70f05172823ebf760d2386d2ebea63cfa72d"
},
{
"member": "run01/workshop_sa_folded-scc-control/receipt.json",
"bytes": 1157,
"sha256": "6de602ddd035e3ee667cb28490da5a6f22e31bc429a8e399c82a55699bc72334"
},
{
"member": "run01/workshop_sa_folded-scc-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_folded-scc-control/stdout.jsonl",
"bytes": 194613,
"sha256": "ddf05a2ca36950305090bd5d91ec2a6c617d2eae373c33ad84e9ff4157581c0c"
},
{
"member": "run01/workshop_sa_folded/receipt.json",
"bytes": 1126,
"sha256": "a8a889e96fb85762531352e331b7486cb297f931a89a6ed57c9464ac294e16fb"
},
{
"member": "run01/workshop_sa_folded/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_folded/stdout.jsonl",
"bytes": 195257,
"sha256": "f24b1412784c6985b79ead9f3fa35dc7818fc20d5ca895d4a03473afa9b3497b"
},
{
"member": "run01/workshop_sa_original-scc-control/receipt.json",
"bytes": 1165,
"sha256": "896734b2abdfef5cd53a98aac2f5770c870bff0a43d7a510168dd275083d4237"
},
{
"member": "run01/workshop_sa_original-scc-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_original-scc-control/stdout.jsonl",
"bytes": 198272,
"sha256": "e30a2a6a30d1522cb2f8e9377e7eb8f0a81d1fe8b5aa18550f78c4829b8cc408"
},
{
"member": "run01/workshop_sa_original/receipt.json",
"bytes": 1134,
"sha256": "b2242a1dddb4811c1d795ef9a3d7a0b6c8bb6eade992b674cfa9a1055a6899d1"
},
{
"member": "run01/workshop_sa_original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_original/stdout.jsonl",
"bytes": 199200,
"sha256": "0517a3088f456fed2ee995bf610e2dbfb0cdc3e4d2e7085c2fbf32d02be15464"
}
]
}
@@ -1,23 +0,0 @@
# Final packaging and claim review
Reviewed the final results and copied source/result/conservation/native reviews, plus the completed evidence archive. This is a bounded publication gate for the existing experiment; no compiler, application, new candidate or native investigation was executed.
**No material packaging or claim error found.** The package is ready for the parent's publication/checkpoint step. This review does not assert that publication has already succeeded, that the candidate is adopted, or that issue32 is complete.
## Archive verification
- `evidence/boundary-order-3e21c1bc.zip`: exactly4,310,136bytes; SHA256 `bb6b896ff2401290869a904f7768ebb52b6f0ab36fada06badbe9abb301c37b8`.
- Exactly156 unique ZIP members; member-name set exactly equals `evidence/manifest.json`, with no duplicate or unexpected member.
- ZIP CRC readback passes for all members. Every uncompressed member's byte size and SHA256 equals its manifest entry.
- Five named native PNG captures are present. The independent result audit script and its explicit SCC helper are both included; the helper dependency is not omitted.
- All relative Markdown links in the topic documents resolve at this checkpoint. The new final review is outside the frozen archive and does not imply a replacement archive hash.
## Claim and attribution checks
Results identify generator/test source `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`, distinguish final15 focused tests/strict Clippy/release gates from earlier14-test evidence at42f595a5, and retain20 candidate outcomes,15 child processes and eight unchanged control streams as distinct inventories. No full-suite, controlled-performance or production acceptance claim is substituted for these scoped checks.
The comparison retains simple-case and chained-parent improvements alongside expanded-workshop crossing/sharing regressions, folded sharing growth, and anchored/local-SCC label problems. Flat full-Project/metric equality and model conservation are attributed to the relevant mechanical audits. Conservation coverage limits are explicit: dormant attachment/translation behavior is not claimed exercised merely because the checker supports it.
Native attribution correctly separates the3e21 candidate Project generator from the reused `d6f45a13a7b8ab8dc9b84ee432a832609f5af6ed` GUI renderer, executable SHA256 `133375d57bdecf3f3effe5ecc13ec121e1257b90838f2cdb64fb91aa9a530d1b`. The planner was not invoked through native Arrange. Four imported Projects and five captures are the observed scope; two other staged controls are not represented as viewed. The independent native review explicitly handles stale window-title metadata, distinguishes readable text from label-background interruption of the parent outline, and limits the local-SCC finding to overview/selection-assisted tracing. No Undo/Redo or production command-integration claim is inferred from these captures.
The final results link the real archive/manifest and bounded reviews, rather than retaining the earlier forthcoming-evidence placeholder. Publication remains the parent's final step. Stop after that requested publication/checkpoint; this review authorizes no further implementation or experiment.
@@ -1,19 +0,0 @@
# One-pass boundary ordering implementation
Owned module only: `examples/auto_layout_probe/condensed/boundary.rs`, preformat SHA256 `d2b1a5882c4b64d79d09d5cca586ad4cef5dac086e5a8fd438f0218e6119889d`. Parent owns integration/format/compilation. No builds, rustfmt, commits or native execution by implementation agent.
Exact requested public-to-parent Block/Band/Group/reorder API. Validates child-parent membership, complete unique band inventory, finite positive block geometry and existing undirected-bundle contiguity. Undirected connectivity is evaluated within each band, preserving existing block order within each indivisible unit; noncontiguous input fails explicitly. Directed incoming edges anchor a unit only when the target lifts into it and source does not lift into the current parent. One vote per distinct visible source placement ID, stable-ID order, f64 arithmetic mean of current absolute source centerY. Full offset ancestry and root40 are composed; parallel edges do not multiply votes.
Only anchored units exchange their previous ordinal slots, using score then canonical unit order. Unanchored unit ordinals remain fixed. Whole-band block heights/gaps are repacked as a prefix, so unequal-height units do not reuse incompatible old Y slots. X, sizes, SCC memberships/ranks, perimeter/member offsets and root layout are untouched. Every member's offset receives its block Y delta; descendants move by ancestor composition rather than duplicate direct edits.
A group is active only if some band contains at least two anchored units. Dependency H→G exists whenever active groupH owns any offset on an actual external source's complete ancestor chain. No additional ancestry-only arcs. Stable parent-ID order feeds SCC condensation; process the dependency DAG once. Every score in one dependency SCC is snapshotted before any member's offset updates. Cycles are therefore a one-pass snapshot heuristic, not a fixed point or a stability guarantee.
Prefix accumulation is f64; conversion and occupied-envelope agreement are checked with explicit0.001units tolerance. Existing canonical prefix positions must also agree within that tolerance. Unchanged orders retain their original f32 positions exactly. No envelope resizing occurs; parent final reprojection remains authoritative. Missing/cyclic/nonfinite structures and excessive charged work return errors. The enclosing candidate owns the private scratch offsets, so it must discard them on failure; this helper does not promise transactional rollback of mutable arguments after an error.
Diagnostics include active parent IDs, dependency edges with source/ancestor witnesses, dependency SCCs/cyclic status, before/after block orders, source-owner sets, actual edge hints, scores, changed units/blocks and tolerance. Pure unrun tests cover anchored sorting with a fixed unanchored ordinal, heterogeneous100/20height repacking, and a source center changing under a grandparent offset. Parent's actual fixtures must test dependency chains/opposition, node/route preservation, repeat behavior and quality; no acceptance is inferred from implementation.
Pre-build review follow-up: module SHA256 `77522e22daf4058a07aafe6b246211bf652d9fc99e2a556cf9f8b20c297eaf0e`. Absolute source Y now follows the final plan's precise f32 order (own offset, ancestors upward, then+40); convert that Y to f64 before adding half-height and averaging votes. Member-offset updates reject actual f32 movement differing from requested delta by more than0.001. Added three unrun tests: actual reorder dependency on a grandparent-owned offset with adversarial parent-ID ordering; actual undirected bundle preservation around an unanchored ordinal with heterogeneous heights and deduplicated sources; noninteger f32 composition plus accepted/rejected translation precision. Six module tests now exist. No policy constants, corpus outcomes or rank/packing heuristics were tuned.
## Parent acceptance addendum
Final tested source3e21c1bca245944ae0ec7bb02aaa920f45f2cc30 corrects full member displacement precision (including origin subtraction), with the real large-origin packing regression. Focused example tests15pass, strict Clippy and optimized Windows build pass with unchanged inputs (gates29–31). Prior gates27–28 at42f595a5 retain14tests/Clippy success. All20candidate outcomes supported inrun01; eightcontrols exact. Result/conservation/native reviews define quality limits; no production adoption.
@@ -1,41 +0,0 @@
# Native renderer observation
Candidate Project generator: `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`.
Reused native executable: `d6f45a13a7b8ab8dc9b84ee432a832609f5af6ed`,
SHA256 `133375d57bdecf3f3effe5ecc13ec121e1257b90838f2cdb64fb91aa9a530d1b`.
This observes saved experimental Projects in the existing renderer. It does not
exercise the experimental planner through a native Arrange command.
The parent used the Computer skill and native Open dialog to import four exact
Project extractions, without editing or saving. Five screenshots record:
1. `01-two-container-boundary`: Fit102%, Left A→Right B and Left B→Right A
appear as separate straight horizontal connections. Both labels are readable
between containers, with no shared route or apparent endpoint ambiguity.
2. `02-two-container-scc`: same viewport/scale, prior SCC ordering. Routes
visually meet at the right container boundary and run alongside its border;
the apparent straight rows misleadingly suggest the opposite endpoint pairing.
This is a concrete improvement from the first image's reordered children.
3. `03-anchored-boundary`: authored anchors retain bent routes. The two label
backgrounds interrupt the right parent border; the label text remains readable
and does not obscure child names. The emitted two label/node intersections
should not be described as two unreadable labels or child-name occlusions.
4. `04-local-scc-boundary`: Fit55%, intact Y1/Y2 block above X1/X2, Z later.
Small text and multiple adjoining/reused strokes make tracing harder than
the simple two-edge example. A structurally correct block order is insufficient
to establish native usability for this case.
5. `05-local-scc-selected-lower-boundary`: selecting the lower source connection
highlights its path to X1 and displays Source B / X1 in Properties. Selection
helps resolve the route among neighboring strokes. No endpoint edit occurred.
The process was closed by Alt+F4. The immediate window list briefly retained the
closing window; a subsequent capture reported no foreground process. The owned
observer then returned exit0, empty stdout/stderr, unchanged immutable inputs,
and no running process. All six staged working JSONs remain unchanged (only four
were opened). No save, undo/redo, new planner invocation, API integration, general
accessibility acceptance, or whole-application acceptance is inferred.
Evidence includes stage/source extraction receipts, per-run process records,
five screenshot/metadata pairs, and the launcher. Package binaries are hash-bound
in the manifest rather than duplicated in the research archive. Windows native
inspection only; Linux remains excluded.
@@ -1,41 +0,0 @@
# Boundary-order native evidence review
Independent review, 2026-09-25. Inspected all five archived PNGs with `view_image`, their capture metadata, the staging/launch/close records, package and source attribution, and the private profile's recent-model list. No new GUI session, import, build, experimental Arrange invocation or source change. This review stops at the existing evidence as requested by the user.
**The simple boundary case is visibly easier to trace than its SCC control. Authored anchors retain a small label-background/container-border conflict, while the local-SCC overview still needs selection to disambiguate a boundary route. This is limited native observation of imported geometry, not acceptance of a production Arrange replacement.**
## Attribution and integrity
- Reused GUI source: `d6f45a13a7b8ab8dc9b84ee432a832609f5af6ed`; executable SHA256 `133375d57bdecf3f3effe5ecc13ec121e1257b90838f2cdb64fb91aa9a530d1b`; DLL SHA256 `aa282fa47bb2c4e210cea5e470cdbdca58568f0be0bc73e404d86ab9cd95ef6a`.
- Imported candidate and paired SCC Projects were generated at `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`. The existing native renderer displays those raw Projects. The experimental boundary planner was not executed through the GUI's Auto-layout control.
- Independently rehashed 21 referenced records covering the manifest, launcher, source-run/child receipts and stdout, reused attribution, staged executable/DLL, six input Projects, launch preflight and native logs: no mismatch. All six working Project hashes agree between the recorded preflight and close inventories; no working-file change was recorded.
- Manifest SHA256 is `940a7605b5a83308261e1fde0ecd7291cc855614a515e87e084823c8fc4e9016`. Private `LOCALAPPDATA` and unrelated working directory are under `boundary-native-20260925/run01`.
- Start/close records identify PID 5492, observed exit code 0, no observer failure, unchanged immutable inputs and empty stdout/stderr. The parent reports closing with Alt+F4. The receipts independently establish observed clean process exit; they do not by themselves establish the particular close gesture or GUI quality.
- The private recent-model list corroborates four imports: simple boundary, simple SCC control, anchored boundary and local-SCC boundary. Two additional staged SCC controls were not observed natively and are not claimed here.
- Several capture JSON window-title fields lag the actual screenshot title, including the first capture's `Untitled mission` and the fourth capture's old two-container title. These fields alone do not identify the loaded Project. The image's visible title/status path and the recent-model entries provide consistent attribution. All capture metadata names the staged executable and the same window ID.
## Visual findings
**01 — Simple boundary, 102% zoom.** Left A and Left B remain in their canonical upper/lower order. The right children are Right B above Right A. Each connection is a separate horizontal line into its matching child. Both route labels are readable between the containers, and their association with the two separate lines is visually clear. This screenshot supports the intended local ordering improvement without a selection aid.
**02 — Paired simple SCC control, 102%.** Right A is above Right B, so the two connections take opposing vertical travel beside the right children. Their vertical portions occupy the same visible corridor near the right-container boundary; direction and connection identity are substantially harder to follow than in 01. The labels remain legible, so the defect should be described as route association/shared travel, not unreadable label text. No native selection trace of this control is archived; exact endpoints continue to be established by the input model and routed evidence.
**03 — Anchored boundary, 102%.** The improved child order remains, but the authored source/target port fractions produce short downward bends at the right side instead of straight connections. Both label strings remain readable. The white label backgrounds reach and interrupt the Right group's left border near the route corridors. This is a real local visual conflict, but describing it as text obscuring the Right child name, an unreadable label, or a blocked arrowhead would overstate what the image shows. The artifact is principally label-background occlusion of the parent outline. The screenshot supports retaining that limitation rather than promoting the metric's label/node count into an unqualified severe text-collision claim.
**04 — Local SCC boundary, Fit 55%.** The Y1/Y2 pair is grouped above the X1/X2 pair, with Z to the right. The grouping and rank structure are visible, but labels are small at this fitted scale and several routes run close together or merge visually. In particular, the unselected Lower boundary approaches the Y2 region before continuing down toward X1; an unaided quick reading could assign it to the wrong nearby node. Whole-diagram fit therefore preserves overview at a readability cost. This image does not support a general claim that coherent SCC blocks make all individual routes easy to trace.
**05 — Selected Lower boundary, 55%.** The highlighted route visibly runs from Source B, turns downward beside Y2 and ends at X1. The properties pane independently names `Lower boundary`, source `Source B · @source_b`, and target `X1 · @x1`. This confirms that the selected relation has the correct endpoint and that selection supplies a useful tracing aid for this witness. It does not eliminate the ambiguity of the unselected overview or establish the readability of every other local route.
## Scope of the result
The existing five observations support a narrow positive result for the simple two-container case, a modest remaining border/label-background conflict with authored anchors, and an unresolved overview/tracing cost for the local-SCC case. They do not test experimental command integration, Undo/Redo, routing edits, repeated Arrange in the GUI, automatic-side capacity cases, all frozen cases, or general accessibility/responsiveness. Existing numerical and conservation reviews remain separate evidence. No further native investigation is proposed as part of this completed checkpoint.
Screenshot SHA256:
| File | SHA256 |
| --- | --- |
| `01-two-container-boundary.png` | `bc4e28a0fcc37cdc4c904993b67e5b018c66a3a0a2ff7c2511fec324e03d5cd7` |
| `02-two-container-scc.png` | `e1c68d66a4eae12c2e2c056858a1d4fc6b5eec8c387ee39b19337abbce7f49cf` |
| `03-anchored-boundary.png` | `8038656c660d826426c36e059997eb955ef8e84db4bdc2d23bcc214f64580c1d` |
| `04-local-scc-boundary.png` | `677057c6870103daeeb31d48a11a5f9b8b8ebb604a7864e71a541a28d6024342` |
| `05-local-scc-selected-lower-boundary.png` | `732cc188a8e8fbe3632d3bd824f218560c5a40afac053d5f8936e62be2699861` |
@@ -1,93 +0,0 @@
# Incoming boundary order experiment
Issue32, following the SCC checkpoint f4fa0c11. Keep the full OA/SA product goal
and production/native acceptance requirements unchanged. This is one isolated
planner comparison with released routing, not a quality-selected parameter sweep.
## Question and fixed candidate
The SCC planner drops a connection from a sibling group's local graph when the
source is outside that group. Root SCC ranking knows which container is upstream,
but the children have no information for matching order across the boundary.
The existing two-container witness has164 shared units and one label/node
collision, while the old layered candidate's incoming-neighbor order has zero
for both. Preserve the SCC candidate's sparse40 structural improvement while
restoring this missing information.
Start from the same canonical SCC plan, before import. Never change its SCC
membership, condensation ranks, internal perimeter walks, node sizes, gaps or
root layout. In each nonroot same-rank band, bundle undirected-connected SCC
blocks as indivisible units with their existing internal order. Unanchored units
retain their ordinal slots. Reorder only anchored units among their old slots,
then repack by prefix sums of unchanged heights and gaps. Old absolute Y slots
cannot be reused for differently sized blocks. Envelopes are mathematically
invariant; finite arithmetic and exact final projection remain checked bounds.
An anchor is an oriented incoming projected edge whose target lies under the
current sibling group and whose source does not. One distinct visible source
placement contributes one vote per unit, independent of parallel relation count.
Scores are the mean of current planned absolute source-center Y coordinates,
summed in stable placement-ID order using f64. Break equal scores by original
unit order. Undirected external edges supply no invented direction or score.
This is a stated center-based heuristic, not a claim to match final port slots.
A group can change only when a band contains at least two anchored units.
Create dependencies from every such active group that owns an offset along an
external source placement's entire ancestor chain to the consuming group.
Include the immediate containing group; do not invent additional hierarchy arcs.
Condense this influence graph and process its SCC DAG deterministically. Before
each SCC, compose a complete absolute-position snapshot from current offsets.
All member groups calculate proposals from that snapshot before committing any
of them. Each group commits once. Cyclic influence therefore has one simultaneous
step, an explicit limitation rather than an unbounded convergence loop.
Recompose descendants through their ancestor offsets. Perform one final original-
to-final placement import, preserving the existing reset/hidden/retained-route
contract and conditional effective-minimum restoration. Exact final projection
and actual mandatory leads must pass; no size/gap/anchor repair is added.
Apply the existing graph, work and extent bounds to new dependency/snapshot work.
## Controls, falsifiers and acceptance
Retain all14 original cases, their SCC run02 outputs at2426d286 and the original,
Arrange-reset and old-layered controls. Flat/no-boundary outputs, particularly
sparse40 and both mixed-ID cases, must preserve complete Project, geometry and
metrics exactly (new diagnostics are separate). Existing SCC-mode and released
route-mode output must remain byte exact after adding the new observer mode.
The existing two-container witness requires Left A before Left B, Right B before
Right A, with actual route sharing/contact/label improvement assessed against
the old zero-sharing witness. Swapping both groups is not that success.
Add three independent topology falsifiers before execution:
1. Opposing parents: L.A→R.B, L.B→R.A, R.A→L.A, R.B→L.B. Contradictory order
demands must remain deterministic, bounded and explicit; zero crossings is
not an achievable requirement inferred from those demands.
2. Three-parent chain: L.A→M.B, L.B→M.A, M.B→R.A, M.A→R.B. Preserve upstream
L.A<L.B, obtain M.B<M.A and R.A<R.B, and preserve root ranks L<M<R.
Compare relation-ID reversal and a uniform authored subtree translation.
3. Two local two-node SCCs X/Y feeding a singleton Z in a later rank, with
external Source.A→Y1 and Source.B→X1. Order Y before X without splitting
either cycle or changing Z's rank/perimeter geometry.
Also run the existing two-container witness with authored source/target port
anchors. Use meaningful pure tests for heterogeneous-height prefix packing,
undirected bundle preservation and complete source-ancestor influence. These
tests supplement rather than replace actual projected Project cases.
Record complete before/after Projects, dependency graph and SCC batches, source
placement/edge hints, scores, before/after unit and block orders, final derived
ports, geometry and warnings. Reconstruct preservation independently, including
folded latent offsets, anchors, other views and eligible route resets. Check
same-input equality, JSON/source roundtrips and ten full repeated calls. Report
explicit refusals without treating a successful observer process as adoption.
Preserve crossings, all contact types, raw and edge-deduplicated shared intervals,
label/node/label/stroke conflicts, enclosure/penetration, route length and area.
Boundary improvement may worsen internal tracing; cyclic influence can retain
crossings; source centers may disagree with fixed or derived ports. Keep those
counterexamples. Stop this one comparison after independent source/result review.
Production command/API/history integration and native route tracing remain
required before accepting an Arrange replacement. Windows only; Linux remains
excluded, and the existing prerelease remains unchanged.
@@ -1,53 +0,0 @@
# Independent boundary-order result review
Primary `boundary-order-20260925/run01`, source3e21c1bca245944ae0ec7bb02aaa920f45f2cc30. Read-only audit of frozen records; no compiler, routing, engine or native execution. **The boundary-order hypothesis passes its exact simple tracing and propagation witnesses while preserving flat SCC results. It is not a monotonic quality improvement or an accepted Arrange implementation.**
## Integrity and all20 outcomes
Verified15 child receipts exit0/not timed out with matching source pin and stdout/stderr hashes; bound inputs exactly unchanged; capture/build/source agreement; eight control streams independently byte-identical to their frozen released/SCC controls. All20 candidate outcomes are supported. All20 recorded same-input comparisons, nine subsequent calls and JSON/source roundtrips are exact, with empty necessary lead diagnostics. These are recorded executable observations, not independently rerun model operations.
Ten actually flat cases preserve their complete candidate Project and full metrics exactly against the SCC baseline: flat_chain_4, chain_7_row_wrap, diamond, crossed_bipartite, authored_detour_and_label, fixed_ports, long_ordinary_labels, mixed_dispatch, mixed_dispatch_edge_ids_reversed and subsystems_40_sparse. Sparse's32-unit sharing and coherent SCC gains are therefore unchanged, as are mixed's known relation-ID sensitivity and other prior limitations.
The remaining ten outcomes are nested_cross_boundary (metrics unchanged), two_containers_reversed_children, both workshop cases, and six new structural fixtures described below. No failed/unsupported row was omitted. Full Project conservation beyond the flat exact comparisons, including folded latent geometry/anchor policy, is the parent's separate audit; this report does not replace it.
## Exact independent witnesses
- Existing two-container: LeftA<LeftB and RightB<RightA both hold in final projected centerY. Sharing164→0, contacts2→0, label/node1→0, route length788→460, area339852 unchanged. No new crossing, node penetration or warning. The result solves the declared ambiguous trace witness without swapping both groups.
- Three-parent chain and its translated/reidentified variants: LeftA<LeftB, MiddleB<MiddleA, RightA<RightB and rootX Left<Middle<Right all hold. Sharing328→0, contacts4→0, label/node3→0, length1492→836, area523604 unchanged. Complete projected node geometry is exact between the ordinary, translated-subtree and relation-ID-reversed variants. This supports propagation and absence of authored-parent-position dependence for these examples, not all graphs.
- Opposing parents: diagnostics correctly show one cyclic dependency component. One simultaneous snapshot changes the right order; the resulting aggregate quality remains baseline sharing68, contacts2, label/node2, length1028 and area336730. Repeated full calls are stable. The contradictory demands were not falsely asserted to be simultaneously satisfiable or zero-cost.
- Two local SCCs: independently reconstructed exact quotient SCCs/ranks remain intact. Y lies wholly above X and Z remains in a later X rank. This passes the structural criterion, but sharing270→278 and label/node1→3 regress; contacts14→9, label/stroke4→3 and length2956→2656 improve. Area1155248 remains unchanged. Correct order is not sufficient quality acceptance.
- Anchored two-container: expected orders pass, sharing111.200012→0 and contacts2→0; length788→565.599976, area unchanged. **Label/node increases1→2.** Preserve this counterexample to a blanket claim that anchoring plus correct order improves all presentation quality.
For all20 supported results, independently reconstructed sibling quotient SCC membership and condensation rank ordering agree with diagnostics. Independent interval sweeps reproduce all emitted raw pairwise sharing totals and also retain distinct-edge physical sharing. No contact/crossing numbers were independently recomputed in this pass; they are explicitly emitted observations. The inherited folded retrace/raw-sharing distinction remains visible rather than silently changing metric definitions.
For the six extra fixtures, independently verified all edge-hint tuples against original projected edges and recomputed21 unit scores from projected source-owner centerY. Applied dependency components in reported order, taking a common pre-update snapshot inside a cyclic component and updating descendants only after its scores. Every score agrees exactly, including chain scores366/202 followed by202/366 downstream. This verifies the concrete evidence chain for these tests; it is not a general proof of dependency scheduling correctness.
## Real workshop tradeoffs
| Metric | Expanded SCC→boundary | Folded SCC→boundary |
| --- | ---: | ---: |
| Proper crossings |6→7|8→6|
| Point contacts |16→15|28→28|
| Raw shared length |344→352|726.5→1077.5|
| Label/node |3→3|3→3|
| Label/stroke |1→1|2→1|
| Route length |7950→7794|8137→8137|
| Drawing area |1600772→1524784|1169964→1127988.592529|
Both retain zero emitted unrelated node penetration/overlap; expanded warnings remain0 and folded warnings remain the same four promoted-endpoint warnings. Expanded gains in length/area/contact count coexist with a new crossing and more sharing. Folded fewer crossings/label-stroke contacts coexist with a351-unit sharing increase. The real-case evidence therefore rules out unconditional quality adoption from the synthetic success alone.
## Decision and next boundary
Retain incoming boundary ordering as a useful mechanism and preserve the one-run evidence. It meets the declared two-container and chained-parent order/tracing targets without disturbing flat SCC geometry. Do not tune this run to remove the counterexamples, and do not describe20 supported/stable cases as20 improved layouts.
Before production integration, investigate the specific new label/node collisions in the anchored and local-SCC witnesses and the newly shared folded workshop routes. Any selection policy must preserve hard geometry/model constraints and make quality tradeoffs explicit; merely choosing the lowest crossing count would favor the folded result while hiding substantially more coincident routing. A local label-aware coordinate/route check or conditional order acceptance is a distinct future design decision, not validation supplied by this run. Native tracing, renderer glyph/header legibility, navigation cost, command/history integration and release acceptance remain outstanding.
No production source change or additional candidate execution was performed by this audit.
- .local\audit-boundary-order-20260925.py: SHA256 96bb938961255b59add3922f2cc8b30ddc7ec127d77ab1d7b61974e116930432.
- .local\audit-scc-placement-v3-20260925.py: SHA256 8b238f010eeb81720a59a0ad290544f87934acb8070e58a3fd25f9eda9f47a0d.
- .local\boundary-order-independent-audit-20260925.json: SHA256 914e39cf9297ab025927b9ba9bae02adee157e3dc7061058e67ee280cb6cb212.
- .local\boundary-order-20260925\run01\receipt.json: SHA256 9aeaeedd81d968d353c48fc32126c7644c452e3b0679ac67ab4fbad7f985ba49.
@@ -1,65 +0,0 @@
# Incoming boundary ordering: experiment results
**Incoming boundary ordering solves the simple two-container and chained-parent tracing witnesses while preserving the flat SCC results. It does not improve every view and is not an accepted replacement for Arrange.** The candidate remains isolated in the example probe; production commands and released routing are unchanged.
Tested source: `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`. The fixed candidate, scope and alternatives are in [plan](plan.md). See [source review](source-review.md), [independent result review](result-review.md), [conservation review](conservation-review.md), and [native observations](native-observation.md) for their separate evidence scopes.
## Question and method
The preceding SCC candidate made cyclic groups coherent but discarded external incoming-neighbor information when ordering children inside different parents. The new mechanism orders eligible sibling SCC blocks using those incoming sources, without changing condensation ranks, internal SCC walks, stored hierarchy or the router. Parent dependency components determine the processing order; cyclic components use one common snapshot. This is a single predeclared candidate, not a parameter sweep or fixed-point convergence claim.
The run contains15 child processes: released routing control, existing small controls, SCC small control, boundary small fixtures, six paired extra fixtures in one stream, and SCC/boundary pairs for five frozen corpus cases. All15 exit0 with unchanged bound inputs. Eight control streams are byte-identical to their previous released/SCC versions. Candidate outcomes are reported separately from process exit status.
All20 cases return candidates and record exact same-input reproduction, nine subsequent calls equal to the first result, and exact JSON/source roundtrips. Necessary lead diagnostics are empty. Independent analysis reconstructs SCC membership and condensation order and reproduces raw collinear-sharing totals; it also retains edge-deduplicated physical sharing so folded route retracing is not hidden. Twenty-one extra-fixture ordering scores and their edge-hint endpoints were independently checked against projected source positions.
## Outcomes against the SCC control
| Case or group | Observed result |
| --- | --- |
| Ten flat cases | Full candidate Project and full metrics exactly unchanged. Includes sparse40 and both mixed relation-ID variants. |
| Nested cross-boundary small fixture | Quality metrics unchanged. |
| Two containers, reversed children | Required LeftA<LeftB / RightB<RightA order; sharing164→0, contacts2→0, label/node1→0, length788→460; area unchanged. |
| Three-parent chain and its translated/reidentified variants | Required orders propagate through all three parents; sharing328→0, contacts4→0, label/node3→0, length1492→836; area unchanged. Projected node geometry is exact across all three variants. |
| Opposing parent dependencies | Stable bounded result under conflicting demands; aggregate quality unchanged: sharing68, contacts2, label/node2. No claim that all demands become simultaneously satisfiable. |
| Two local SCCs | Y precedes X without splitting SCCs or changing Z's later rank. Contacts14→9 and length2956→2656 improve; sharing270→278 and label/node1→3 worsen. |
| Anchored two-container variant | Required order and exact authored-anchor contract; sharing111.200012→0 and contacts2→0, but label/node1→2. |
| Expanded workshop | Crossings6→7, sharing344→352; contacts16→15, length7950→7794 and area1600772→1524784. Label/node3 and label/stroke1 remain. |
| Folded workshop | Crossings8→6 and label/stroke2→1; sharing726.5→1077.5, contacts28 unchanged. Four promoted-endpoint warnings remain. |
The ten flat cases are flat_chain_4, chain_7_row_wrap, diamond, crossed_bipartite, authored_detour_and_label, fixed_ports, long_ordinary_labels, mixed_dispatch, mixed_dispatch_edge_ids_reversed and subsystems_40_sparse. Their exact preservation retains both the preceding sparse improvement and its unresolved label issues, as well as mixed's existing ID-sensitive routing differences.
All candidates report zero unrelated node penetration and node overlap. This necessary geometric safety is not proof of label readability or easy tracing. The anchored/local-SCC label regressions and workshop sharing/crossing tradeoffs prevent a blanket quality-pass claim. Complete model conservation, dormant routing metadata and folded latent geometry are assessed separately in the linked conservation review.
## Native observation and limits
The parent's observation covers four Projects and five captures, including a selected lower boundary connection. It supports the improved simple-case trace appearance. In the anchored case, readable label text/backgrounds interrupt a parent border; the local-SCC traces remain difficult at55% zoom. These are bounded visual observations, not evidence that all labels or real workshop tasks pass. The linked native note records the exact artifacts/actions and is authoritative for those claims.
Compilation, successful candidate construction and repeated stability do not establish production readiness. The mechanism does not solve every conflict, and lower crossing count can coexist with more shared ink. No release replacement, issue closure, production command/history integration or general readability acceptance follows. Stop this frozen experiment; retain its counterexamples before selecting further label/connection placement work.
## Reproduction
Use the tested source pin and the recorded Windows native toolchain/environment. Focused gates29–31 pass15 example tests, strict Clippy and the optimized probe build:
```text
cargo test --locked --offline -p oa-core --example auto_layout_probe
cargo clippy --locked --offline -p oa-core --example auto_layout_probe -- -D warnings
cargo build --release --locked --offline -p oa-core --example auto_layout_probe
```
Earlier gates27–28 at `42f595a5d6df92432aaf6965194bf651cd9b8b6d` retain14 passing focused tests and strict Clippy. They are earlier-source evidence, not additional tests at the final pin. No broader test-suite or performance claim is made.
The portable probe interfaces used by the runner are:
```text
auto_layout_probe --route-corpus MANIFEST
auto_layout_probe
auto_layout_probe --scc-fixtures
auto_layout_probe --boundary-fixtures
auto_layout_probe --boundary-extra-fixtures
auto_layout_probe --scc-placement PROJECT_JSON DIAGRAM_UUID
auto_layout_probe --boundary-placement PROJECT_JSON DIAGRAM_UUID
```
The extra-fixture stream carries paired baseline/boundary records. Named corpus rows are associated with their runner case paths, not the generic external_case label. Each child has a90-second timeout; measured durations here are process receipts, not controlled latency benchmarks.
The [evidence manifest](evidence/manifest.json) binds all156 archive members: exact inputs, receipts/logs, audits, native captures and collectors. [Archive](evidence/boundary-order-3e21c1bc.zip):4,310,136bytes, SHA256 `bb6b896ff2401290869a904f7768ebb52b6f0ab36fada06badbe9abb301c37b8`. The [independent native review](native-review.md) bounds the visual claims and documents stale capture-title metadata. Reproduce the independent result audit with `audit-boundary-order-20260925.py RUN_ROOT UNIQUE_OUTPUT_JSON`; its explicit `audit-scc-placement-v3-20260925.py` helper must accompany it. Original controls and full candidate Projects/geometry must remain available; summary tables alone are insufficient to reproduce the comparison.
@@ -1,62 +0,0 @@
# Incoming boundary order source review
**Final source verdict at `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`: no unresolved material findings.** The complete-displacement precision defect found in the initial pin is repaired and independently re-reviewed below. This accepts the source for the bounded experiment, not layout quality, repeated-call stability, production integration or release readiness.
Independent source review of `42f595a5d6df92432aaf6965194bf651cd9b8b6d`, 2026-09-25. Inspected the clean pinned worktree, `harness/experiments/boundary-order-20260925/plan.md`, `crates/oa-core/examples/auto_layout_probe/condensed.rs`, its `condensed/boundary.rs` module, `boundary_fixtures.rs`, and the observer/CLI changes in `auto_layout_probe.rs`. No source edits, compiler, engine/router execution or GUI work. One read-only PowerShell single-precision arithmetic calculation confirms the finding below. Runtime gates belong to the parent and are not claimed by this review.
## Initial verdict at 42f595a5
The implementation follows the settled dependency-SCC ordering policy, with one bounded numerical preservation finding: the final member translation guard checks addition precision but does not check the precision lost while subtracting the old block origin. Fix or explicitly narrow that claimed bound before treating source review as complete. No semantic SCC, projected endpoint, dependency scheduling, undirected bundle or importer-boundary defect was found by this review.
## Resolved finding: guard the complete intended displacement
**P2, `condensed/boundary.rs:358` and `:73`.** `let delta = y - old` rounds the requested block-origin displacement to f32. `translate(value, delta)` then compares the actual addition against that already-rounded displacement. An exact addition can therefore pass even when the member no longer preserves its original offset from its block origin within the declared 0.001 bound.
Concrete single-precision witness:
| Quantity | Value |
| --- | ---: |
| Old block Y | 65536 |
| New block Y, f32 representation of 100.002 | 100.00199890136719 |
| Original member Y, block + 32 | 65568 |
| Computed f32 delta | -65435.99609375 |
| Returned member Y | 132.00390625 |
| Current translate-check error | 0 |
| Member-relative-offset error | 0.0019073486328125 |
These coordinates fit the planner's 100000 extent. A reachable prefix setup uses heights `[65404, 68, 100, 68.002]`, gap 32, original block origins `[0, 65436, 65536, 65668]`, and reversed order `[3,2,1,0]`. The original third block moves from 65536 to approximately 100.002. Every new starting prefix is small, so the packing cast bound does not independently eliminate the witness. The importer checks the resulting node plan against projection; it does not compare the members against their declared block-origin displacement, so that final guard is not a substitute.
Recommended narrow repair: give the translation helper old and new block origins and compare the final f32 member coordinate to `f64(value) + f64(new_origin) - f64(old_origin)`. Reject if the total displacement error exceeds 0.001. A direct regression should cover the witness, alongside the existing addition-rounding case. This is a correctness guard repair, not a layout-quality change or a reason to relax projection equality.
## Confirmed control flow and invariants
- Root isolation is structural: only `Some(parent)` groups are passed to the new module. Root offsets, sizes, semantic component membership, ranks, perimeter walks and gaps remain owned by the existing canonical planner.
- Units come from connected components of bidirectional same-band undirected arcs. The existing canonical BFS order is retained, and noncontiguous bundles are rejected. Sorting permutes whole units; unanchored unit identities retain ordinal slots. Flattening a reordered unit sequence retains each bundle's internal block order.
- Boundary membership uses projected edge endpoints and the same ancestry lift operation as the SCC planner. Only oriented edges entering the group from outside supply anchors. Deduplication uses visible source placement IDs in a BTreeSet, rather than relation IDs or unprojected semantic owners. Edge hints affect diagnostics only.
- `offset_owner` maps every direct child placement to its ordering group. Dependency walks begin at the source placement itself and inspect every ancestor, including the immediate containing group. Restricting graph vertices to groups with at least two anchored units is sound under fixed unanchored slots. No additional hierarchy arcs are invented.
- Dependency SCCs are condensed and processed in deterministic topological order. Every score for a complete SCC is materialized before any offset commits. Commits touch disjoint directly owned offsets; source center recomposition subsequently reads all current ancestor offsets. Cyclic SCCs therefore use the declared common snapshot without a hidden traversal-order preference.
- Center composition now follows the final plan's f32 child-to-root addition order, then adds the root origin and converts to f64 for half-height and mean computation. This resolves the preliminary review concern about scoring a different absolute-position arithmetic path.
- Packing uses unchanged dimensions and gaps, rebuilds prefix positions rather than reusing old heterogeneous slots, and checks canonical prefix consistency, cast precision and total extent. An unchanged order retains its original f32 origins. Mathematical envelope invariance is supported; the unresolved member-displacement finding above is distinct.
- Edge scanning, ancestry traversals, component discovery, dependency traversal, topological scans, source-center reconstruction and member commits charge the shared bounded work counter. The existing visible/stored graph bounds and final extent guard remain. This is a weighted work bound, not an instruction-count or elapsed-time guarantee.
- The module only mutates the local plan. `candidate_policy` imports once after all reordering; the existing exact reprojection, effective-minimum restoration, original-to-final route handling and final mandatory-lead check remain unchanged. A refusal cannot partially mutate the caller's Project.
- The original SCC mode takes the false policy branch. By source inspection its planner and emitted observer structure are unchanged; byte equivalence still requires the planned controls. The new extra-fixture CLI emits both baseline and boundary observations rather than presenting its process exit as candidate acceptance.
## Test and fixture assessment
The pinned source adds six module tests. The ancestor-dependency test deliberately gives the downstream parent a lower ID, so omitting the grandparent influence arc would produce a wrong downstream permutation; it exercises actual `reorder`, not merely center arithmetic. The undirected test exercises a whole bundle around an unanchored unit, heterogeneous prefix packing, and deduplicated source owners. Other tests cover anchored ties, ordinary heterogeneous swapping, ancestor coordinate composition, final-plan f32 evaluation order and addition precision rejection. These are meaningful mechanism checks by inspection; this review does not claim they have run.
Projected fixture additions cover opposing parents, a three-parent propagation chain, relation-ID reversal, authored subtree translation, two local SCCs with a downstream singleton, and authored endpoint anchors. They support the declared experiment. They do not establish general automatic-side capacity stability, dormant authored-route coverage, native readability, production command/history integration or release readiness.
The result review must retain cyclic conflicts, source-center versus attachment-order mismatch, internal-rank versus boundary preference conflict, exact repeated-call stability, semantic/route conservation, and the complete quality vector. The mathematical ordering properties alone do not establish those outcomes.
## Repair re-review at 3e21c1bc
Independently inspected the clean pinned worktree and the complete diff from `42f595a5d6df92432aaf6965194bf651cd9b8b6d` to `3e21c1bca245944ae0ec7bb02aaa920f45f2cc30`. The only source change is the intended precision repair and its regression. No source edits or compiler/engine execution were performed by this reviewer.
`translate` now receives the old and new block origins. It calculates `f64(value) + (f64(new_origin) - f64(old_origin))`, converts that complete intended coordinate to f32, and rejects if the final coordinate differs by more than 0.001. The commit site no longer constructs or adds a rounded f32 delta. This closes the demonstrated subtraction-rounding loophole without changing ordering, scores, sizes, gaps or projection rules.
The new `member_offset_survives_large_origin_subtraction` test uses the complete four-block prefix witness, reverses its order, and checks preservation of the third block member's 32-unit offset after the move. The earlier precision rejection and center-composition tests remain. There are now seven boundary module tests by source inspection. Their execution is parent-owned; this source review does not import earlier gate success from another commit as evidence for this pin.
Reviewed `condensed/boundary.rs` SHA256 at the repaired pin: `c6b17ac1e16bc1d12fe3625d4633c83891f8c0bd7716c96c31295cae0f8588da`.
The initial finding above is retained as evidence and is **resolved at 3e21c1bc**. No further material source issue was identified. The runtime/quality and coverage limits stated above remain unchanged.
@@ -1,36 +0,0 @@
# Independent reference-adapter review
2026-09-25. Static review only; no engine/compiler/router/GUI execution or source edits. Parent owns JavaScript review and execution. Reviewed local experiment plan, Python supervisor, Rust importer diff and adjacent baseline/prototype observation contracts. Read the JavaScript output-check interface only to establish where importer preconditions are enforced.
**Verdict: no blocking source defect found for the frozen five-case diagnostic run, subject to consuming structurally passing outputs and the explicit post-import checks below.** This is readiness for experiment execution, not adapter fidelity, native traceability, or production acceptance. Compilation remains unverified here.
Reviewed SHA256:
- Plan `.local/connection-layout-reference-plan-20260925.md`: `41a420db7ee039fa424f60b61097bddc6eff787e2705004e1c88b19f8b97c371`.
- Supervisor `.local/run-elk-reference-20260925.py`: `114d2fd4dbc9a55cd57c4b5175989686dc413863fc2a62fa4a71278792937066`.
- Importer `crates/oa-core/examples/auto_layout_probe.rs`: `95666ce866111d0626e964483fc954276e258bd0ef61a4f96b9857a0ceab468e`.
- Rehashed frozen released geometry: `9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2`, matching the parent's declared input.
## Concrete checks and result-consumption requirements
1. **Freeze pin improvement:** the supervisor asserts manifest and bundle pins and records all other bound hashes, including geometry, before/after. It does not assert the expected geometry SHA above. Add that single expected-input assertion before execution; otherwise a different preexisting geometry file can be consistently recorded without matching the intended frozen dataset. Current inspected bytes do match, so this is a narrow provenance improvement, not an observed wrong input. No generalized dependency framework is needed.
2. **Only import structurally passing output.** Rust `import_placement` rejects unsupported Scenario, schema mismatch, excess nodes/edges, missing/extra/duplicate IDs, nonfinite/nonpositive rectangles and translated nonfinite positions. It deliberately has no independent minimum-size/header/child-containment checks and no parent field in `PlacementPlan`; those gates are supplied by JavaScript inspection. Parent must require the per-case structural result and success receipt before extracting `{schema:1,nodes:[{id,position,size}]}`. Do not rank a transferred failed structural result as an ordinary candidate. Core validation is not a substitute for those geometric checks. Reprojected Rust bounds should also be compared with intended transferred bounds to detect core size normalization.
3. **Compare final physical ports, not only unchanged anchors.** Importer does not import ELK port positions; its final projected ports are therefore the right raw material for comparing owner/semantic-port identity and final intended tip to ELK's output. Unchanged authored fraction and unchanged ELK relative pixel offset can still diverge after compound resizing. Plan correctly declares this a transfer limitation requiring assessment. A candidate with such divergence is not evidence of faithful fixed-port optimization, even if both separate geometries validate.
4. **Use the matching baseline.** The existing `observe` result's `after` is released Layout without the new reset. The comparable baseline is `reset_only_control`, which clears effective routes after that Layout. The old prototype and importer clear using pre-operation eligibility, while the control's legacy helper uses post-Layout routed `!custom_suspended`. For the frozen unchanged-visibility cases this may agree, but verify actual eligible edge sets and resulting route records before attributing differences solely to placement. Do not relabel the old `after` metrics as reset-only.
5. **Conservation summary does not prove the route contract.** `conservation` masks routes and node geometry for broad semantic comparisons; `authored_routes_exact=false` is expected after reset. Independently compare complete per-edge records: entry/order, attachments, exact eligible reset, and retained `translated_routes` result. Roundtrip and conservation booleans are emitted observations, not asserted by the CLI; consuming analysis must inspect them. Exit0 alone does not pass them.
## Importer correctness within this scope
Eligibility is captured from the original projection before movement and requires actual owners equal projected endpoints with both visible. The importer clones the original, changes only selected-view node geometry, clears eligible pins/full labels, and applies the existing original-to-final `translated_routes` helper only to retained routes. Entries are updated in place; route order and endpoint attachments are preserved. Other views and semantic records remain untouched by construction.
The revised collapsed rule is appropriate: compare proposed size to the original compact projected size exactly, update position, preserve stored expanded size. Temporary unfolding is used only to recover core visual ancestry, including Allocation grouping; it is not returned or used to change visibility. Hidden nodes found under a visible collapsed ancestor receive that ancestor's translation, preserving their latent relative geometry. The ancestry walk is bounded and detects cycles/missing parents. This implementation does not establish a general policy for unrelated filtered descendants omitted even from the unfolded projection; the stated policy leaves unrelated omitted placements exact. Do not extrapolate beyond the frozen fixtures.
The importer cannot reverse semantic edges or accept replacement ports because neither exists in its plan schema. Its 256 stored-node /1024 visible-edge limits and Scenario refusal are explicit. Original-to-final positional deltas are calculated before retained-route translation; no intermediate Layout or independently validated Batch prefix is introduced. This remains an example-only geometry transfer, not a new production command or history implementation.
## Supervisor and attribution
The supervisor creates a fresh output directory and exclusive log files; each engine case has a separate subprocess with a90-second timeout. Python's `subprocess.run` timeout kills/waits for its child and the loop retains an explicit timeout/error receipt before proceeding. The reviewed contract uses the bundled engine in that Node process; this is not a general descendant-process supervisor. Before/after bindings cover Node, adapter script, geometry, manifest, bundle, dependency receipt, plan and supervisor. JavaScript receipts separately hash raw case/graph/mapping/result/observation files. Parent should retain both receipt layers.
The supervisor can exit0 even when individual cases fail or time out; its final record explicitly preserves those outcomes. Require every expected case receipt, no timeout, success plus structural checks before treating that case as transferable. Failed/unsupported cases stay visible in the comparison. Timing includes process work and is correctly disclaimed against earlier Rust route-only timings.
The plan correctly limits the claim to whether engine placement transfers usefully through released routing and label placement. Raw ELK routes/labels are diagnostic, never secretly turned into authored constraints. Estimated label extents, fixed-position port drift, prototype folded refusal and absent native trace acceptance remain real limitations. A failed placement transfer cannot reject ELK's complete coupled drawing architecture; a scalar gain cannot establish an engineer's correct trace or label association. No request is made for new fixtures, option sweeps, production dependencies or additional architecture before this bounded run.
@@ -1,40 +0,0 @@
'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const crypto = require('node:crypto');
const {adapt, inspect} = require('./reference_probe.cjs');
const nodes = [
{id:'parent', element:'ep', visual_parent:null, collapsed:false, position:{x:100,y:200},size:{width:300,height:300}},
{id:'child', element:'ec', visual_parent:'parent', collapsed:false, position:{x:124,y:264},size:{width:100,height:80}},
{id:'sink', element:'es', visual_parent:null, collapsed:true, position:{x:600,y:264},size:{width:100,height:80}},
];
const ports = [
{owner:'child',element:'out',side:'Right',position:{x:224,y:304}},
{owner:'sink',element:'in',side:'Left',position:{x:600,y:304}},
];
const edges = ['one','two'].map(id=>({id,oriented:true,source:'child',target:'sink',source_port:'out',target_port:'in'}));
const row = {fixture:'synthetic',diagram:'d',before_project:{diagrams:{d:{nodes:Object.fromEntries(nodes.map(n=>[n.id,n]))}}},
before:{projected_nodes:nodes,projected_ports:ports,projected_edges:edges,
routed_edges:edges.map(e=>({id:e.id,label:{text:e.id,size:{width:30,height:24}}}))}};
const {graph,mapping} = adapt(row);
assert.equal(mapping.ports.length,2);
assert.equal(graph.edges[0].sources[0],graph.edges[1].sources[0]);
const result = inspect(graph,mapping);
assert.equal(result.structural_checks_passed,true);
assert.deepEqual(result.nodes.find(n=>n.id==='child').position,{x:124,y:264});
assert.deepEqual(result.ports.find(p=>p.owner==='child').position,{x:224,y:304});
const badSize=structuredClone(graph); badSize.children.find(n=>n.id==='sink').height+=1;
assert(inspect(badSize,mapping).checks.some(c=>c.name==='collapsed_compact_size_exact'&&!c.passed));
const underHeader=structuredClone(graph); underHeader.children[0].children[0].y=2;
assert(inspect(underHeader,mapping).checks.some(c=>c.name==='child_inside_parent_body'&&!c.passed));
const reversed=structuredClone(graph); reversed.edges[0].sources=['sink'];
assert(inspect(reversed,mapping).checks.some(c=>c.name==='edge_orientation_and_endpoints'&&!c.passed));
const missing=structuredClone(row); missing.before.projected_edges[0].source_port='unknown';
assert.throws(()=>adapt(missing),/Missing projected semantic port/);
const undirected=structuredClone(row); undirected.before.projected_edges[0].oriented=false;
assert.throws(()=>adapt(undirected),/Unsupported undirected/);
const duplicate=structuredClone(row); duplicate.before.projected_nodes.push(duplicate.before.projected_nodes[0]);
assert.throws(()=>adapt(duplicate),/duplicate/);
console.log(JSON.stringify({checks:'passed',scope:'synthetic adapter mapping only; engine not invoked',
checks_exercised:['nested coordinate roundtrip','shared physical port reuse','collapsed size rejection','header intrusion rejection','edge reversal rejection','missing semantic port rejection','undirected rejection','duplicate node rejection'],
adapter_sha256:crypto.createHash('sha256').update(fs.readFileSync(require.resolve('./reference_probe.cjs'))).digest('hex')}));
@@ -1,56 +0,0 @@
# Connection-aware arrangement: independent criteria and next experiment
Proposed engineering decision for issue32, 2026-09-25; not an accepted requirement, production adoption, or native acceptance. Read the frozen independent routing results, decision-review and adoption-rubric under `harness/experiments/routing-independent-20260925` at local auto-layout HEAD `ac5d7ef34a567f45b72adbd30d1a243f5811ba73`, and reset `crates/oa-core/src/session.rs::layout` at `956e33e568c6b799d0330803c74927e205977dfd`. No code, compiler, router or GUI execution in this review.
**Recommendation: run the bounded ELK placement-reference comparison on the existing frozen five-case corpus.** Compare current Arrange/reset placement, the existing native layered prototype, and ELK-derived node placement through the unchanged released Rust router and label placement. Freeze one ELK configuration and adapter policy before results. This tests a missing architectural choice; further J/L coefficient or lane tuning does not.
## What the existing evidence establishes
Current Layout orders roots from projected connections, but places roots in rows of four and stacks children vertically; it does not use routed conflicts or label extents when placing them. Reset removes eligible authored bends and labels, making a new route possible; it does not make those node positions connection/label-aware.
The routing-only results are useful counterexamples to a scalar objective. L reduces workshop shared length1042→602 while adding a label/node and label/stroke collision. Reversed mixed IDs change132→233.5999756 shared length; sparse reduces496→372 but proper crossings24→25. Timing screens pass, and these finite outcomes do not identify either J or L as a general improvement. The retained released router remains a controlled reference, not a quality oracle.
Raw contacts, shared intervals, crossings and collision identities locate potential reading problems. They do not measure whether an engineer follows the intended connection: a short ambiguous junction at a decision point can matter more than a long common-terminal stub; a correct readable crossing can be preferable to coincident edges. Pairwise shared length also counts pair multiplicity, not just unique occupied ink. Area, bends and length expose costs; none identifies correct label-to-edge association or legible arrowheads. Keep raw quantities and concrete identities, with no weighted quality-pass total.
## Architecture choices and falsifiers
| Choice | Useful hypothesis | Smallest decisive contrary observation |
| --- | --- | --- |
| Connection-aware placement, then released routing and label placement | Better sibling order, layering and space allocation remove the dominant conflicts without a new routing architecture. | A faithful placement improves graph order but the released routing/label stage repeatedly recreates the named ambiguity, with no trace-task gain. This falsifies sufficiency on these cases, not every possible placement algorithm. |
| Bounded placement/routing/label feedback | A small number of specific gap/order corrections can repair conflicts left by the first pass. | A repair relocates ambiguity to another required task, or repeated passes oscillate/expand the scene without eliminating the conflict. Do not start this loop before identifying a concrete failed constraint from the placement comparison. |
| Coupled external engine output, including routes and labels | Jointly reserving routes and label space achieves benefits lost by independent downstream routing. | Engine output cannot faithfully express fixed ports, compound geometry or projection semantics, or its apparent visual gain depends on violating them. A placement-only failure is insufficient evidence against this choice. |
ELK Layered is a relevant reference because it explicitly supports ports, labels and compound graphs; this is a capability basis for the experiment, not a predicted win. [ELK Layered](https://eclipse.dev/elk/reference/algorithms/org-eclipse-elk-layered.html)
## One bounded comparison
1. Keep the existing five input Projects and their manifest hashes. Reuse the declared source-to-target tasks, including companion fan-out branches and the fixed ID permutation. Do not add favorable graphs or change names/IDs after viewing outputs.
2. Use one common reset policy for all three placement arms: eligibility captured from the original staged projection; eligible stored pins/full label cleared; attachments retained. Apply existing `translated_routes` to retained routes using each arm's actual final deltas. Current Arrange/reset is the baseline. Comparing an unreset baseline with a reset candidate would confound placement with stale-constraint removal.
3. Freeze engine/version, options, seed, input ordering, dimensions and mapping policy. Run the existing native prototype unchanged. Its folded/omitted-node rejection is an unsupported result, not permission to unfold the Project or omit the case from the table. Report supported subsets explicitly.
4. Emit the final cloned Project plus real Rust projection/routes/labels for each supported arm, and the unchanged raw ELK input/output. Preserve ELK edge sections and label locations for diagnosis, but do not store them as authored Project bends/labels in the placement-only arm. Engine labels can influence spacing while the displayed Rust label lands elsewhere; such a result must not be described as successful label placement.
5. Audit adapter invariants before quality ranking. Reuse independent contact metrics; inspect every changed collision/warning identity. Run the same predeclared trace tasks against the actual rendered result for any candidate that advances beyond geometric screening. Keep all failures and unsupported outputs.
6. Stop after this fixed comparison and concrete adapter-defect repairs. No option sweep, per-case best seed or penalty tuning. A faithful ELK placement gain motivates a production-placement decision; a faithful failure localizes what placement alone did not solve. If raw ELK output looks better but Rust rerouting loses the benefit, the next bounded question is transferring or reproducing that coupling, not more node-order heuristics. Raw output is diagnostic evidence only until rendered and audited with equal constraints.
## Adapter gates that can invalidate the experiment
- **Placement identity and hierarchy:** map by placement identity, not semantic element alone; a view can place the same semantic entity more than once. Use actual projected visual parents and visible endpoints, while preserving the authored containment model. Convert every nested local coordinate to Project coordinates exactly once. ELK distinguishes child shapes and edge sections; preserve its raw coordinate representation for diagnosis. [ELK JSON format](https://eclipse.dev/elk/documentation/tooldevelopers/graphdatastructure/jsonformat.html)
- **Cross-container edges:** explicitly configure hierarchy handling. Root default behavior separates children, whereas `INCLUDE_CHILDREN` allows one run across hierarchy levels. A silently flattened graph or independently laid-out children would not test compound connection-aware arrangement. [ELK hierarchy handling](https://eclipse.dev/elk/reference/options/org-eclipse-elk-hierarchyHandling.html)
- **Port identity:** one adapter port per physical projected placement/semantic-port identity, reused by its multiple edges. Duplicating shared ports per edge makes fan-out artificially easy; merging distinct ports changes the problem. Keep direction and semantic edge identity through any engine cycle reversal; never write a reversed semantic source/target back to Project.
- **Port position and resizing:** preserve authored side/fraction and dormant explicit attachments. Compare final Rust physical port tips to the adapter's final intended tips, not to original global coordinates that should move with nodes. ELK exposes both `FIXED_RATIO` and `FIXED_POS`; select a verified policy rather than treating them as synonyms. Fixed original pixel offsets on a resized container can cease to match our fractional anchor. Either demonstrate final-size fraction mapping, or mark that case unsupported; post-correcting only Rust ports makes the optimizer's assumed geometry stale. [ELK port constraints](https://eclipse.dev/elk/reference/options/org-eclipse-elk-portConstraints.html)
- **Node sizes and occupied content:** preserve leaf minimum sizes, container body/header/footer clearances, port extents and State row geometry where applicable. Compound resizing is an explicit geometric output and must contain children below the header. ELK supports fixed size constraints, but these do not by themselves supply ARCADIA's content rules. [ELK node-size constraints](https://eclipse.dev/elk/reference/options/org-eclipse-elk-nodeSize-constraints.html)
- **Labels:** supply the same declared label text/dimension policy across arms; ELK generally expects label dimensions from its caller. Estimated rectangles remain screening evidence. Preserve full text and use actual rendered ink for readability acceptance. Do not promote ELK label coordinates into persisted authored overrides to improve this arm. [ELK JSON labels](https://eclipse.dev/elk/documentation/tooldevelopers/graphdatastructure/jsonformat.html)
- **Folded and dormant geometry:** use promoted visible endpoints for planning, but do not replace actual semantic ownership. Retain dormant route metadata with the existing translation rule, and preserve collapse/filter state. If moving/resizing a folded owner requires a hidden-placement transform the adapter cannot represent faithfully, report unsupported rather than shifting hidden geometry opportunistically. Other views remain exact.
An identity import/export without layout should recover the exact Project; only explicitly permitted geometry/reset fields may differ after layout. Validate Projects and independently audit output IDs, finite geometry, container containment, endpoints and anchors. Passing `validate_candidate` alone cannot prove geometric containment or adapter fidelity.
## Proposed acceptance gates
**Preservation is a hard gate.** Semantic elements, relations, endpoints, roles, authored ownership, aliases/text/source meaning, projection/filter/fold state, route entry order and attachment data remain exact. Only selected-view arrangement geometry and eligible pin/full-label reset change; ineligible pins follow existing translation rules, including the State boundary exception. Hidden placement handling follows the declared Layout scope, not a blanket “hidden never moves” rule. Missing actual owners, filtered edges and promoted endpoints are ineligible for reset. Other views stay exact. After integration, enclosing Batch remains one transaction; a valid pending property Apply is a separate history action; invalid drafts block Arrange; clean Undo/Redo and persistence/source round trips retain the established contract. This experiment does not change Process/Scenario path behavior.
**Geometric screening is identity-aware.** Reject new missing routes, nonfinite geometry, invalid containment, unrelated node/header penetrations, or new warnings absent a specifically documented unavoidable constraint. Retain existing failures per edge. Report actual new/resolved label collisions and contacts, not net totals. Do not require zero crossings on arbitrary graphs or count intended ancestor-body containment as an obstacle defect.
**Traceability is the adoption gate.** For every frozen named task, the reviewer must identify the correct source, target, direction and associated connection label in the rendered diagram. Include both branches of shared ports and both distinct ports; inspect actual arrowheads and text. Record wrong turns, ambiguity, selections, pan/zoom and completion time. Normal selection is allowed but record whether unselected geometry was ambiguous and whether selection repaired it. Use the same declared readable scale and viewport, plus Fit for overview; unlimited zoom must not hide unusable navigation cost. Require an observed improvement in a declared task or correction of a baseline failure, with no new failed/ambiguous task. If both layouts already complete every task cleanly, do not manufacture a correctness win from a smaller scalar score; report clarity/action costs descriptively.
**Robustness and cost are separate.** Same-input repeats must be deterministic; ten repeated Arrange applications should settle rather than ratchet size or oscillate. The fixed edge-ID permutation must preserve semantics and task correctness; pixel-identical output for every graph symmetry is not required. Timing must cover placement plus Rust routing/label work, and report engine startup/serialization separately and as end-to-end cost. Existing route-only timing ceilings do not establish acceptable total Arrange latency. Declare any new end-to-end budget before timing; disclose unsupported cases and censored runs.
This comparison can reject an architecture assumption or justify one next prototype. It cannot establish universal optimality, all-Unicode label measurement, arbitrary graph scalability, or native usability from screenshots/metrics alone. It requires no production dependency on JavaScript and makes no recommendation to ship ELK before the adapter and trace evidence exist.
@@ -1,32 +0,0 @@
{
"package": "elkjs",
"version": "0.12.0",
"registry_url": "https://registry.npmjs.org/elkjs/0.12.0",
"tarball_url": "https://registry.npmjs.org/elkjs/-/elkjs-0.12.0.tgz",
"integrity": "sha512-YZcKynxVxYoKIOEpywEPwCFdg+BTbxQRNf3pbwdDCvc8O3kQD8bmIwSxKU1eOTVc4Xo+VG9Te+575mlfvOrhEQ==",
"tarball_sha256": "c1d7719723e020b10724e3ccbc935696a2884f1e78d361cdd03766309e8e8e2a",
"license": "EPL-2.0 OR GPL-3.0-or-later",
"members": [
{
"path": "lib/elk.bundled.js",
"bytes": 1609707,
"sha256": "1222e44f953ce7746af23801e723708f8e6f436b8b377a6a5fc7552f34a307b3"
},
{
"path": "package.json",
"bytes": 1687,
"sha256": "4614a8db12f1c46a1d988d55e92012286c5a25dde3ea69be7695013f4d23cf02"
},
{
"path": "LICENSE.md",
"bytes": 14443,
"sha256": "637e81f4a1b6b4079535c499fca05e238cf7605c1ff5b76d60d7da7ce96700c9"
},
{
"path": "README.md",
"bytes": 15957,
"sha256": "a83dbb420b0b4f335f4b9d2ca65c335be3fdcf83248bff49f81582b9c0c30712"
}
],
"scope": "Isolated reference experiment; no install scripts or production dependency."
}
File diff suppressed because it is too large Load Diff
@@ -1,9 +0,0 @@
# Final connection-layout claim review
Read-only review; no material blocker to archiving the bounded research report. Reviewed `.local/connection-layout-results-20260925.md` SHA256 `ddf74fe85c9764f6b5162562d0de5b51489b29ef1e765337ed59da01871bc669` against frozen transfer audit `18274aff78240bed1ccfbbe49491e49465156db6cca6a934149a699e603459e4`, geometry result review, and sparse diagnosis `44d30974fe30183459412e177acc3729afeb448cf69ea05097afe037ecc1d93d`.
The report accurately separates final fc5c22c9 observer from initial8a2010d8, released routing from experimental placement, and independent Arrange-reset work. Counts, preserved identity correction, automatic-port drift, explicit anchored-port fidelity and pure-transform limitations agree with my readback. The width1 failed negative expectation is preserved; the separate height1 rejection is accurately described. Final strict-Clippy receipt was inspected. This is not full-workspace, native readability, production adoption, or publication acceptance.
The clearance diagnosis appropriately supersedes the earlier narrower uninflated-corridor inference. The result does not claim that raw ELK is feasible under core18-unit leads/12-unit clearance, or that increasing search budgets would repair a rejected terminal pair. Necessary30-unit separation is explicitly not sufficient for an entire route. Both unsupported workshop cases remain coverage refusals, not engine failures or compound successes.
Two nonblocking wording improvements were sent to parent: say “10 of25 total port positions change, all automatic” because the denominator includes six authored ports; say “policy-aware conservation” rather than implying every raw conservation boolean is true (mixed authored_routes_exact is intentionally false after reset). No report edits by reviewer. The artifact is ready for bounded local archival with existing failed attempts and limitations retained; no reruns performed.
@@ -1,7 +0,0 @@
# Identity transfer correction after first run
The initial source8a2010d8 importer wrote every expanded node's projected size to its stored size. Independent audit of five identity plans showed unwanted source normalization:3 nodes in workshop original,2 in folded,10 in each mixed case and40 in sparse. Projection minimum sizing had made those effective rectangles larger than stored authored sizes. Positions, effective geometry, semantics, route policy and collapsed stored size were not implicated, but a no-layout identity transfer did not recover the original Project apart from eligible reset.
Correct the adapter by preserving stored size whenever the planned rectangle equals the original projected rectangle. Only an actual effective size change is imported. Keep collapsed compact-size equality mandatory and never replace its stored expanded size. After transfer, reproject and require the entire intended node ID/position/size map to match exactly, rejecting a requested rectangle that Rust would renormalize. Preserve first-run receipts and outputs; rerun the identical Rust control/import/negative cases against the corrected source without rerunning or tuning ELK.
This is an example-only adapter repair, not a production layout change. It cannot resolve the independently observed automatic-port drift:10/25 ports in each mixed case and48/110 in sparse differ materially from the engine's assumed endpoints, with7/32 side changes respectively. All six authored anchors in each mixed case remain exact. Geometry comparisons remain diagnostic until that mapping limitation is addressed.
@@ -1,11 +0,0 @@
# Parent observations for the placement comparison
Parent read complete JavaScript adapter and Rust importer source before execution; independent source review covered importer and supervisor. Synthetic Node checks executed with exit0 against adapter SHA2569cc91aa45deb86bfc0c4b786eb0d5e89336dd3e3bfef1adac5560b840ccc8b4a: nested coordinate roundtrip, shared physical port reuse, collapsed size change/header intrusion/edge reversal/missing semantic port/undirected/duplicate-node rejection. Engine was not invoked by those checks. This paragraph transcribes the observed tool result; it is not an independently signed process receipt.
One official pinned elkjs0.12.0 configuration ran across all five frozen cases. Three flat cases passed structural checks; both workshop cases refused the declared unsupported undirected edge before any engine call. Failed case receipts remain. No configuration changed after observing geometry.
Rust comparison supervisor first stopped before any child invocation due Python's copied Windows environment using uppercase SYSTEMROOT. Original package capture and failed script were retained in rust-run01; correcting case lookup produced rust-run02. Fourteen children completed with their expected outcomes. This is a tooling failure, not an application crash.
The parent inspected same-scale offline schematics for mixed dispatch reset and imported ELK placement. The imported arrangement makes the main sequence more continuous, with a long feedback path around it and a wider drawing. The reset arrangement wraps the flow across three rows with several crossing/shared paths. These images show boxes/lines and estimated label rectangles, not native glyphs or successful trace tasks. No GUI or native workflow was executed for this reference experiment.
Independent review found two distinct issues: unwanted identity size normalization, corrected in an example-only follow-up; and automatic-port divergence from ELK assumptions, retained as a hard limitation. The sparse imported drawing also produces a NoClearPath and an unrelated-node penetration. Source and model validity do not override these findings. No engine adoption, production change, issue closure or publish success is claimed.
@@ -1,33 +0,0 @@
# Connection-aware placement reference experiment
Prepared before reference-engine outputs. Owned scope remains issue32 under Codex-ytr83r/root. Gitea writes are currently failing; this plan and future results remain local-only until normal publication succeeds. No Linux checks or prerelease change.
## Question and decision
Can a mature port/hierarchy/label-aware placement engine produce node positions that materially improve the unchanged released Rust router's final drawing on the already frozen five-case corpus? Compare the old Rust layered prototype, reset-only released placement, and this external placement reference. This is a diagnostic comparison, not adoption of JavaScript into the product and not a test of ELK's complete drawing quality: returned ELK edge sections and label coordinates are deliberately not applied to the Project. Failure may show that placement and routing must stay coupled, or that this adapter is inadequate; it does not establish that ELK itself is poor.
The previous turn completed a verified explicit route-reset contribution. Prior J/P/PL/L router tuning stopped with realistic ID-order/label tradeoffs. Root cause inspection shows production Layout topologically orders roots then packs four per row; nested children are ordered by ID and stacked. Its isolated layered prototype uses neighbor node centers, ignoring fixed port order, and one diagram-wide maximum label gap. Repeating penalty tuning is not the next experiment.
Primary sources: [ELK Layered](https://eclipse.dev/elk/reference/algorithms/org-eclipse-elk-layered.html) supports ports, labels and compound graphs; [Schulze et al.](https://rtsys.informatik.uni-kiel.de/~biblio/downloads/papers/jvlc13.pdf) explains that crossing reduction depends on port order as well as node order. [ELK JSON](https://eclipse.dev/elk/documentation/tooldevelopers/graphdatastructure/jsonformat.html) defines nested nodes/ports and requires supplied label dimensions. [Official elkjs](https://github.com/kieler/elkjs) exposes the layout algorithms in JavaScript. These motivate a reference comparison, not an inferred implementation guarantee.
## Frozen inputs and engine
Use every existing case in `harness/experiments/routing-independent-20260925/corpus/manifest.json` at research commitac5d7ef3: workshop expanded/folded, mixed dispatch, its fixed edge-ID permutation, sparse40. Do not edit fixtures, select favorable routes or add new tuning cases after results. Manifest SHA256 `a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717`. Reuse named trace tasks and report every case, including unsupported/error outcomes.
Reference engine elkjs0.12.0, official npm tarball SHA256 `c1d7719723e020b10724e3ccbc935696a2884f1e78d361cdd03766309e8e8e2a`, bundle SHA256 `1222e44f953ce7746af23801e723708f8e6f436b8b377a6a5fc7552f34a307b3`. Registry SHA512 integrity was verified. Isolated bundle extraction runs no npm lifecycle scripts. Dependency receipt and license retained. No application dependency or packaging decision follows.
One declared configuration: layered, RIGHT, orthogonal, hierarchy INCLUDE_CHILDREN, seed1, no edge/hierarchy merging. Projected visible hierarchy and dimensions; semantic port identities shared exactly where projection shares them. Ports use observed owner-relative coordinates, side and FIXED_POS. Compound header64/top padding and24 side/bottom padding reflect these architecture fixtures; they are not general State metrics. Current core-estimated edge label dimensions are supplied. Save complete input graph before calling the engine. Unsupported direction/port references fail explicitly. Record all output coordinates, sections and labels even though only node geometry is transferable.
## Adapter gates and attribution
Return exactly one finite positive node rectangle for each input projected node, with unchanged IDs and hierarchy. Detect extra/missing/duplicate nodes, changed identity, invalid fields, shrinkage and header/containment collisions. Do not change semantic endpoints, port anchors, relation direction, node visibility/collapse, authored endpoint attachments, or other views to fit the engine. Output port coordinates relative to resized containers must be audited: FIXED_POS can diverge from our final-size anchored fractions. Report that divergence; do not silently accept it as matching a fixed-fraction constraint or repair anchors. Reproject the imported Project through Rust to establish its actual final endpoints.
The placement importer starts from the original Project and replaces only returned visible node geometry. A visible collapsed node has a compact projected footprint distinct from stored expanded size: require the returned size to equal that compact footprint, apply only position, and preserve stored expanded size. A resized collapsed footprint is rejected in this first adapter, not silently written into expanded geometry. For a hidden placement under a visible collapsed ancestor, translate its original position by the nearest visible collapsed ancestor's delta, preserving latent relative geometry; unrelated out-of-projection nodes stay exact. This is an explicit reference-adapter policy, not a production amendment. Use existing actual-owner translation for retained routes; clear only pre-operation eligible visible actual-owner pins and full labels, preserving entries/order and attachments as in the verified reset contract. Validate the final Project, source roundtrip and conservation before geometric comparison. Scenario is excluded explicitly. The old prototype's folded refusal remains a failure to support that case, not a zero-score row.
## Observations and stopping rule
Parent bounds each engine process at90seconds; retain timed-out/missing output as failure. Engine timing is diagnostic startup+layout timing and is not directly compared to prior isolated Rust route-only timings. Freeze binaries/scripts/config/source before calls; verify input and tool hashes afterward. No concurrent compiler writes to shared target. Once compiled, preserve the observer executable before further worktree edits.
Report the existing full vector: proper crossings, all raw T/bend/endpoint contacts, pairwise and nonterminal shared length, node/header penetration, node and estimated-label collisions, unrelated label/stroke intersections, per-edge warnings, bends, length and area. No weighted aggregate pass. Compare each candidate to the same source/reset control; distinguish node positions from final routed geometry. Preserve source inputs and raw outputs. ID-permutation pair must stay explicit.
This finite experiment answers whether further native Rust placement design or an external-engine integration spike has stronger evidence. A simpler Rust candidate remains preferred if comparable. Reject a transfer as acceptable if it loses constraints, changes semantic records, produces invalid geometry or introduces new trace ambiguity. Scalar improvements alone cannot establish native traceability or shipped usability. Follow native inspection only for a candidate with a defensible full quality vector and faithful adapter; no automatic production adoption. Stop after this single configuration and analysis; repair concrete adapter defects with preserved failures, but do not tune options after viewing quality results.
@@ -1,37 +0,0 @@
"""Fetch pinned official reference engine, without install scripts or production changes."""
from pathlib import Path
import base64, hashlib, io, json, tarfile, urllib.request
root = Path(__file__).resolve().parent / 'elk-reference-20260925'
root.mkdir(exist_ok=False)
url = 'https://registry.npmjs.org/elkjs/0.12.0'
metadata_raw = urllib.request.urlopen(url, timeout=30).read()
metadata = json.loads(metadata_raw)
assert metadata['name'] == 'elkjs' and metadata['version'] == '0.12.0'
tar_url = metadata['dist']['tarball']
assert tar_url == 'https://registry.npmjs.org/elkjs/-/elkjs-0.12.0.tgz'
raw = urllib.request.urlopen(tar_url, timeout=30).read()
expected = 'sha512-YZcKynxVxYoKIOEpywEPwCFdg+BTbxQRNf3pbwdDCvc8O3kQD8bmIwSxKU1eOTVc4Xo+VG9Te+575mlfvOrhEQ=='
actual = 'sha512-' + base64.b64encode(hashlib.sha512(raw).digest()).decode()
assert actual == expected == metadata['dist']['integrity']
(root / 'registry-metadata.json').write_bytes(metadata_raw)
(root / 'elkjs-0.12.0.tgz').write_bytes(raw)
allowed = {'package/lib/elk.bundled.js', 'package/package.json', 'package/LICENSE.md', 'package/README.md'}
members = []
with tarfile.open(fileobj=io.BytesIO(raw), mode='r:gz') as archive:
for member in archive.getmembers():
if member.name not in allowed:
continue
assert member.isfile()
data = archive.extractfile(member).read()
relative = Path(member.name).relative_to('package')
destination = root / relative
destination.parent.mkdir(exist_ok=True)
destination.write_bytes(data)
members.append({'path': relative.as_posix(), 'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()})
assert len(members) == len(allowed)
receipt = {'package': 'elkjs', 'version': '0.12.0', 'registry_url': url, 'tarball_url': tar_url,
'integrity': actual, 'tarball_sha256': hashlib.sha256(raw).hexdigest(),
'license': metadata['license'], 'members': members, 'scope': 'Isolated reference experiment; no install scripts or production dependency.'}
(root / 'dependency-receipt.json').write_text(json.dumps(receipt, indent=2)+'\n', encoding='utf-8')
print(json.dumps(receipt))
@@ -1,239 +0,0 @@
'use strict';
// Isolated placement reference. No Project mutation or ELK route/label adoption.
const fs = require('node:fs');
const path = require('node:path');
const crypto = require('node:crypto');
const REFERENCE_DIR = __dirname;
const SOURCE = path.resolve(REFERENCE_DIR, '../routing-corpus-runs-20260925/geometry-released/stdout.jsonl');
const SOURCE_SHA256 = '9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2';
const BUNDLE_SHA256 = '1222e44f953ce7746af23801e723708f8e6f436b8b377a6a5fc7552f34a307b3';
const sha = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
const binding = file => { const b = fs.readFileSync(file); return {path: file, bytes: b.length, sha256: sha(b)}; };
const write = (dir, name, value) => fs.writeFileSync(path.join(dir, name), JSON.stringify(value, null, 2) + '\n', {flag: 'wx'});
const requireThat = (ok, message) => { if (!ok) throw new Error(message); };
const finite = (...values) => values.every(Number.isFinite);
const unique = (values, key, label) => {
const result = new Map();
for (const value of values) {
requireThat(typeof value[key] === 'string' && !result.has(value[key]), `Missing/duplicate ${label} identity`);
result.set(value[key], value);
}
return result;
};
const portId = (owner, element) => `port:${owner}:${element}`;
const SIDES = {Left: 'WEST', Right: 'EAST', Top: 'NORTH', Bottom: 'SOUTH'};
const CONFIG = {
'elk.algorithm': 'layered', 'elk.direction': 'RIGHT',
'elk.edgeRouting': 'ORTHOGONAL', 'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
'elk.randomSeed': '1', 'elk.layered.mergeEdges': 'false',
'elk.layered.mergeHierarchyEdges': 'false',
};
function adapt(row) {
const metrics = row.before;
const nodes = unique(metrics.projected_nodes, 'id', 'node');
const definitions = unique(metrics.projected_edges, 'id', 'edge');
const routed = unique(metrics.routed_edges, 'id', 'routed edge');
const graph = {id: 'reference-root', layoutOptions: {...CONFIG}, children: [], edges: []};
const objects = new Map();
const mapping = {case: row.fixture, diagram: row.diagram, nodes: [], ports: [], edges: [],
excluded_source_placements: [], configuration: CONFIG,
scope: 'Transferable projected placement only. ELK routes/label positions are diagnostic and never applied to Project.',
port_policy: 'Zero-size FIXED_POS anchors at observed node-relative physical port positions. Drift and resizing require explicit assessment.',
compound_policy: 'Input size is minimum; top padding64, other padding24. Leaves retain input dimensions.'};
for (const node of nodes.values()) {
const parent = node.visual_parent === null ? null : nodes.get(node.visual_parent);
requireThat(node.visual_parent === null || parent, `Missing parent of ${node.id}`);
const seen = new Set([node.id]);
for (let p = parent; p; p = p.visual_parent === null ? null : nodes.get(p.visual_parent)) {
requireThat(!seen.has(p.id), `Hierarchy cycle at ${node.id}`); seen.add(p.id);
}
requireThat(finite(node.position.x, node.position.y, node.size.width, node.size.height)
&& node.size.width > 0 && node.size.height > 0, `Invalid node geometry ${node.id}`);
const object = {id: node.id, x: node.position.x - (parent?.position.x || 0),
y: node.position.y - (parent?.position.y || 0), width: node.size.width, height: node.size.height,
layoutOptions: {'elk.portConstraints': 'FIXED_POS'}, ports: [], children: []};
objects.set(node.id, object);
mapping.nodes.push({id: node.id, element: node.element, parent: node.visual_parent,
collapsed: node.collapsed, input_world: node.position, input_size: node.size});
}
for (const node of nodes.values()) {
const object = objects.get(node.id);
(node.visual_parent === null ? graph : objects.get(node.visual_parent)).children.push(object);
}
for (const object of objects.values()) {
if (object.children.length) Object.assign(object.layoutOptions, {
'elk.padding': '[top=64,left=24,bottom=24,right=24]',
'elk.nodeSize.constraints': '[MINIMUM_SIZE]',
'elk.nodeSize.minimum': `(${object.width},${object.height})`,
});
else object.layoutOptions['elk.nodeSize.constraints'] = '[]';
}
const portMap = new Map();
for (const port of metrics.projected_ports) {
const owner = nodes.get(port.owner), id = portId(port.owner, port.element);
requireThat(owner && !portMap.has(id) && SIDES[port.side], `Invalid/duplicate port ${id}`);
requireThat(finite(port.position.x, port.position.y), `Invalid port coordinates ${id}`);
const object = {id, x: port.position.x - owner.position.x, y: port.position.y - owner.position.y,
width: 0, height: 0, layoutOptions: {'elk.port.side': SIDES[port.side]}};
portMap.set(id, object); objects.get(port.owner).ports.push(object);
mapping.ports.push({id, owner: port.owner, element: port.element, side: port.side,
input_world: port.position, input_relative: {x: object.x, y: object.y}});
}
for (const edge of definitions.values()) {
requireThat(edge.oriented === true, `Unsupported undirected edge ${edge.id}`);
const endpoint = end => {
requireThat(nodes.has(edge[end]), `Missing ${end} node for ${edge.id}`);
const semantic = edge[`${end}_port`];
if (semantic === null) return edge[end]; // Explicit automatic node endpoint; never invent a port.
const id = portId(edge[end], semantic);
requireThat(portMap.has(id), `Missing projected semantic port ${id} for ${edge.id}`);
return id;
};
const source = endpoint('source'), target = endpoint('target');
const observed = routed.get(edge.id);
requireThat(observed && observed.label && finite(observed.label.size.width, observed.label.size.height)
&& observed.label.size.width >= 0 && observed.label.size.height >= 0, `Missing/invalid label ${edge.id}`);
const object = {id: edge.id, sources: [source], targets: [target], labels: [{id: `label:${edge.id}`,
text: observed.label.text, width: observed.label.size.width, height: observed.label.size.height}]};
graph.edges.push(object);
mapping.edges.push({id: edge.id, projected: edge, elk_sources: [source], elk_targets: [target],
observed_route: observed, label_measurement: 'Existing core estimated rectangle; no renderer measurement'});
}
requireThat(definitions.size === routed.size, 'Projected/routed edge inventory differs');
for (const node of Object.values(row.before_project.diagrams[row.diagram].nodes)) {
if (!nodes.has(node.id)) mapping.excluded_source_placements.push(node);
}
return {graph, mapping};
}
function inspect(result, mapping) {
const nodes = [], ports = [], edges = [], checks = [];
const add = (name, passed, detail) => checks.push({name, passed: Boolean(passed), detail});
function finiteTree(value) {
if (typeof value === 'number') return Number.isFinite(value);
if (Array.isArray(value)) return value.every(finiteTree);
if (value && typeof value === 'object') return Object.values(value).every(finiteTree);
return true;
}
add('all_engine_numeric_fields_finite', finiteTree(result));
function walk(container, ox, oy, parent) {
for (const node of container.children || []) {
const x = ox + node.x, y = oy + node.y;
nodes.push({id: node.id, parent, position: {x, y}, size: {width: node.width, height: node.height}});
add('finite_positive_node', finite(x, y, node.width, node.height) && node.width > 0 && node.height > 0, node.id);
for (const port of node.ports || []) {
ports.push({id: port.id, owner: node.id, position: {x: x + port.x, y: y + port.y},
relative: {x: port.x, y: port.y}, size: {width: port.width, height: port.height}});
add('finite_zero_size_port', finite(port.x, port.y, port.width, port.height)
&& port.width === 0 && port.height === 0, port.id);
}
walk(node, x, y, node.id);
}
edges.push(...(container.edges || []));
}
walk(result, 0, 0, null);
const actualNodes = unique(nodes, 'id', 'result node'), actualPorts = unique(ports, 'id', 'result port');
const actualEdges = unique(edges, 'id', 'result edge');
const sameIds = (actual, expected) => actual.size === expected.length && expected.every(v => actual.has(v.id));
add('node_inventory', sameIds(actualNodes, mapping.nodes));
add('port_inventory', sameIds(actualPorts, mapping.ports));
add('edge_inventory', sameIds(actualEdges, mapping.edges));
const resizing = [], portDrift = [];
for (const input of mapping.nodes) {
const output = actualNodes.get(input.id); if (!output) continue;
add('parent_identity', output.parent === input.parent, input.id);
const compound = mapping.nodes.some(n => n.parent === input.id);
const dx = output.size.width - input.input_size.width, dy = output.size.height - input.input_size.height;
resizing.push({id: input.id, compound, width_delta: dx, height_delta: dy});
add(compound ? 'compound_minimum_size' : 'leaf_size_exact', compound ? dx >= -1e-6 && dy >= -1e-6 : dx === 0 && dy === 0, input.id);
if (input.collapsed) add('collapsed_compact_size_exact', dx === 0 && dy === 0, input.id);
if (input.parent !== null) {
const parent = actualNodes.get(input.parent);
add('child_inside_parent_body', parent
&& output.position.x >= parent.position.x + 24 - 1e-6
&& output.position.y >= parent.position.y + 64 - 1e-6
&& output.position.x + output.size.width <= parent.position.x + parent.size.width - 24 + 1e-6
&& output.position.y + output.size.height <= parent.position.y + parent.size.height - 24 + 1e-6, input.id);
}
}
for (const input of mapping.ports) {
const output = actualPorts.get(input.id); if (!output) continue;
add('port_owner_identity', output.owner === input.owner, input.id);
portDrift.push({id: input.id, before: input.input_relative, after: output.relative,
dx: output.relative.x - input.input_relative.x, dy: output.relative.y - input.input_relative.y});
}
for (const input of mapping.edges) {
const output = actualEdges.get(input.id); if (!output) continue;
add('edge_orientation_and_endpoints', JSON.stringify(output.sources) === JSON.stringify(input.elk_sources)
&& JSON.stringify(output.targets) === JSON.stringify(input.elk_targets), input.id);
}
return {nodes, ports, checks, resizing, port_relative_drift: portDrift,
structural_checks_passed: checks.every(c => c.passed), adoption_accepted: false,
limitation: 'ELK sections/labels are only in raw result. Compound resize and fixed-port drift are measurements requiring explicit transfer review, not automatic acceptance.'};
}
async function main() {
const [caseName, destination, sourceArgument, bundleArgument, ...extra] = process.argv.slice(2);
requireThat(caseName && destination && extra.length === 0,
'Usage: node reference_probe.cjs CASE_NAME OUTPUT_NEW_DIR [SOURCE_JSONL [ELK_BUNDLE]]');
const sourcePath = sourceArgument ? path.resolve(sourceArgument) : SOURCE;
const bundlePath = bundleArgument ? path.resolve(bundleArgument) : path.join(REFERENCE_DIR, 'lib/elk.bundled.js');
const out = path.resolve(destination);
fs.mkdirSync(out, {recursive: false}); // Refuse overwrite, including any existing directory.
const receipt = {case: caseName, success: false, adoption_accepted: false,
started: new Date().toISOString(), timeout_policy: 'Parent supervisor supplies90s process limit; no in-process hard timeout.'};
try {
receipt.script = binding(__filename); receipt.input = binding(sourcePath);
receipt.engine = {package: 'elkjs', version: '0.12.0', ...binding(bundlePath)};
requireThat(receipt.input.sha256 === SOURCE_SHA256, 'Frozen source JSONL hash mismatch');
requireThat(receipt.engine.sha256 === BUNDLE_SHA256, 'Pinned elkjs0.12.0 bundle hash mismatch');
if (!bundleArgument) {
const dependencyPath = path.join(REFERENCE_DIR, 'dependency-receipt.json');
receipt.dependency_receipt = binding(dependencyPath);
const dependency = JSON.parse(fs.readFileSync(dependencyPath, 'utf8'));
requireThat(dependency.package === 'elkjs' && dependency.version === '0.12.0', 'Wrong dependency pin');
for (const member of dependency.members) {
const actual = binding(path.join(REFERENCE_DIR, member.path));
requireThat(actual.sha256 === member.sha256 && actual.bytes === member.bytes, `Dependency mismatch ${member.path}`);
}
} else {
receipt.dependency_receipt = null;
receipt.dependency_policy = 'External bundle admitted by exact pinned bundle SHA256; local extraction receipt not required.';
}
const rows = fs.readFileSync(sourcePath, 'utf8').trim().split(/\r?\n/).map(JSON.parse);
const cases = rows.filter(row => typeof row.fixture === 'string');
receipt.available_cases = cases.map(row => row.fixture);
requireThat(cases.length === 5 && new Set(receipt.available_cases).size === 5, 'Expected five distinct frozen cases');
const row = cases.find(value => value.fixture === caseName);
requireThat(row, `Unknown case ${caseName}`);
write(out, 'source-case.json', row);
const {graph, mapping} = adapt(row);
write(out, 'input-graph.json', graph); write(out, 'adapter-mapping.json', mapping);
receipt.input_graph = binding(path.join(out, 'input-graph.json'));
receipt.adapter_mapping = binding(path.join(out, 'adapter-mapping.json'));
const ELK = require(bundlePath);
const elk = new ELK();
const started = process.hrtime.bigint();
const result = await elk.layout(graph, {layoutOptions: CONFIG});
receipt.engine_elapsed_ns = (process.hrtime.bigint() - started).toString();
write(out, 'elk-result.json', result);
const observed = inspect(result, mapping);
write(out, 'placement-observation.json', observed);
receipt.success = observed.structural_checks_passed;
receipt.outputs = ['source-case.json','input-graph.json','adapter-mapping.json','elk-result.json','placement-observation.json'].map(name => binding(path.join(out, name)));
receipt.input_unchanged = binding(sourcePath).sha256 === receipt.input.sha256;
receipt.engine_unchanged = binding(bundlePath).sha256 === receipt.engine.sha256;
requireThat(receipt.input_unchanged, 'Frozen input changed during engine call');
requireThat(receipt.engine_unchanged, 'Pinned bundle changed during engine call');
if (!receipt.success) process.exitCode = 1;
} catch (error) {
receipt.success = false; receipt.error = {message: error.message, stack: error.stack}; process.exitCode = 1;
} finally {
receipt.finished = new Date().toISOString(); write(out, 'receipt.json', receipt);
}
}
module.exports = {adapt, inspect, CONFIG}; // Parent can exercise synthetic adapter cases without invoking ELK.
if (require.main === module) {
main().catch(error => { console.error(error.stack || error); process.exitCode = 1; });
}
@@ -1,55 +0,0 @@
# Independent geometry review of the placement reference
2026-09-25. Reviewed recorded `elk-reference-20260925/rust-run02` results at source `8a2010d8a6033201d6efd742134dae9f3d235632`, plus original `run01` engine receipts and selected raw ELK geometry. No compiler, router, engine or GUI rerun. Only read-only arithmetic on recorded points/rectangles was executed. Port/Project conservation is the separate gate reviewer's responsibility; this report does not substitute for that audit.
**Decision: the imported ELK placement provides a real hypothesis for further connection-aware arrangement, but this output is not adoptable.** The mixed cases improve several independent geometric problems through the unchanged Rust router. Sparse40 introduces a new unrelated-node penetration and `NoClearPath`, and uses substantially more area and total route length. Both compound workshop cases were rejected by the adapter before the engine ran, so this experiment supplies no external-engine compound-layout result. There is no scalar winner or native traceability claim.
## Complete case accounting
Values in each cell are reset-only control / old native layered prototype / imported ELK placement. Shared length retains raw pairwise multiplicity, including common-terminal intervals. All numbers are recorded geometry, not readable-ink guarantees.
| Case | Proper crossings | Raw point contacts | Shared length | Label/node collisions | Result limitation |
| --- | --- | --- | --- | --- | --- |
| Workshop original |6 /7 /unsupported|27 /20 /unsupported|1832 /1467 /unsupported|1 /1 /unsupported|ELK adapter refused undirected edge before engine call. Native uses more area and route length despite fewer shared units.|
| Workshop folded |7 /unsupported /unsupported|19 /unsupported /unsupported|1194 /unsupported /unsupported|0 /unsupported /unsupported|Native refuses folded/omitted topology; ELK adapter refuses the same undirected edge.|
| Mixed dispatch |10 /7 /1|25 /24 /7|716.39998 /4228 /238|0 /0 /0|ELK gains require larger area; native exchanges crossings for extensive shared runs.|
| Mixed reversed IDs |9 /7 /1|26 /24 /7|512.39998 /4228 /238|0 /0 /0|ELK aggregate metrics match the original mixed case; this alone does not prove all corresponding routes identical.|
| Sparse40 |94 /17 /20|158 /83 /55|1990 /40522 /666|14 /1 /0|ELK introduces one unrelated-node penetration and one NoClearPath.|
The baseline here is explicitly `reset_only_control`, not the unreset `after`. In mixed dispatch, unreset Layout reports7 crossings whereas the reset control reports10/9; substituting the former would hide the reset/placement distinction. Original authored input is also not the Arrange baseline: original mixed has0 crossings/shared132, and original sparse has24 crossings/shared496 but70 estimated label/node collisions. Therefore “better than current Arrange” must not be shortened to “better than the authored input in every respect.”
The native prototype reports exact same-input repeats, idempotence, and equality to its first result for passes2–10 in all four supported cases. Folded remains unsupported, not stable by omission. Stability does not redeem its shared-run costs: mixed4228 and sparse40522 are real recorded totals, not nondeterministic noise. This run does not establish repeated-ELK-Arrange idempotence.
## Actual gains and costs
For either mixed ordering, ELK reduces bends39→20 and total route length10618.60→9361.00. Estimated label/node, label/label and unrelated label/stroke collisions remain zero; no node penetration or warning is emitted. Area grows1139880→1808460, about59%. This is a plausible improvement in connection tracing with a navigation/overview cost still requiring native inspection. It shows that changing placement alone can help this graph through the released router; it does not require adopting external edge sections to obtain every benefit.
Sparse ELK reduces bends152→80; estimated label/node14→0, label/label1→0 and label/stroke31→0. These are substantial geometric improvements. However, route length rises39660→64223 and drawing area3804920→12840450, about3.37 times the baseline. The emitted bounds are8735 by1470 diagram units. Any later readable-scale trace test must account for the resulting navigation, rather than declaring readability from an uncluttered thumbnail. Native layered uses area6020910 and length54282, with fewer proper crossings17, but shared length40522 is much worse. Neither dominates the full vector.
Workshop original native reduces sharing1832→1467 and contacts27→20, but adds a crossing6→7, length8480→9251 and area886464→1125534. Its label/node count stays1 and label/stroke stays0. Folded reset retains four promoted-endpoint warnings and eliminates the original NoClearPath (original warning total5→reset4); neither alternative supplies a folded result. The failed ELK case receipts identify undirected edge `22c7011d-b559-5df8-aadd-851002904ba0`; this is an adapter coverage refusal, not evidence that ELK failed to solve those compounds.
## Independently checked geometry
Reused the independent axis-interval mathematics in `audit-routing-corpus-contacts-20260925.py`, without its route-only CLI or any routing call. Applied it to all12 available reset/native/ELK scenes. All48 comparisons agree within0.001: unique pairwise point contacts, proper crossings, common physical-terminal point contacts, and positive pairwise shared length. The arithmetic retains raw sharing; a zero common-terminal point-contact count does not mean shared terminal intervals are absent.
Independent classification for imported mixed is1 proper +2 T +4 bend contacts =7; sparse is20 proper +28 T +7 bend contacts =55. Thus most remaining sparse contacts are not proper crossings. They cannot be erased from interpretation by quoting only20 crossings.
For all nine flat mixed/sparse scenes, independently intersected emitted label rectangles with node rectangles, label rectangles with each other, and unrelated orthogonal strokes with label interiors. All27 collision-count comparisons agree. These checks concern the supplied estimated rectangles; they do not measure actual glyphs, port labels, selection hit behavior or arrowheads. Compound ancestor exclusions were not independently recomputed here.
**Confirmed sparse blocker:** relation `flow_45`, “Assessment Decide handoff to Planning Aggregate,” ID `00000000-0000-0000-0000-00000003347d`, passes through unrelated “Assessment Package” placement `00000000-0000-0000-0000-000000030dd1`. The node occupies x4522..4746, y660..820. The Rust route has a vertical segment x4634, y495..822, crossing160 units of its interior (Rust's epsilon-inset metric reports159.9998). Its actual source/target owners are different placements, so this is not endpoint or ancestor-body containment. The same edge emits `NoClearPath`; reset/native sparse have zero such penetrations and warnings.
The raw ELK section for that same edge has identical tips (4120,477)→(4634,840), but follows bends (4120,498), (4502,498), (4502,830), (4634,830). It goes left of the identified obstacle and then below it, avoiding that particular node. This supplies a concrete local witness that the placement had an avoidance corridor which the released routing result did not use. It does not prove that the raw ELK route avoids every other obstacle or that full raw ELK routing/labels pass our entire rubric.
## Implication and bounded next decision
Do not adopt this placement-only transfer while the sparse hard failure remains, and do not conclude that all improvement requires a coupled engine: mixed supplies the contrary positive example. The sparse witness makes a targeted compatibility investigation worthwhile. Compare that one fixed scene/edge's released-router search/fallback constraints against the recorded feasible ELK corridor. Determine whether the lost route is a bounded router limitation or an incompatible spacing/clearance assumption before choosing a broader coupled-route integration. Preserve the frozen outputs; do not sweep ELK parameters to hide the blocker. Compound reference coverage still requires an explicit undirected-edge policy before any claim about hierarchy-aware arrangement can be tested.
No native task was performed in this review. No renderer-based legibility, timing winner, semantic-port fidelity, full conservation or production acceptance follows from the arithmetic. Those remain separate gates.
Evidence hashes, SHA256:
- `rust-run02/arrange-corpus/stdout.jsonl`: `f924af4038ade0de2e0f44988fa28d2566019d8c4bc2bde70e61fe4813364d40`.
- `rust-run02/mixed_dispatch-elk/stdout.jsonl`: `9308079aa4804d6a61fae724fc4fe44807528fc20b03e213ad08d5b4314c2d89`.
- `rust-run02/mixed_dispatch_edge_ids_reversed-elk/stdout.jsonl`: `567ef210022639083654e43c900ad82c7ba529597d437386c7b27baac2d4e58f`.
- `rust-run02/subsystems_40_sparse-elk/stdout.jsonl`: `37ef8db5a920a50a1ed12eba08913fee810d02226d920fc9018088c9e7b14c3a`.
- `run01/subsystems_40_sparse/elk-result.json`: `9763cda98e744040e1f2e9ad63662cf6e699e8fbdc7e77b388d60ab4303a4282`.
@@ -1,64 +0,0 @@
# Connection-aware placement reference: result and decision
**Do not adopt either placement candidate from this experiment.** The external reference gives a useful mixed-network placement hypothesis, but it assumes port positions that Rust later recomputes and produces an incompatible sparse placement. The native prototype also has large shared-route regressions. The next design must account for automatic-port selection and mandatory exit/obstacle clearance during placement. Increasing routing search limits does not address the diagnosed failure.
This is branch-specific research for issue32, not a production change or an integrated release. Tested final observer source `fc5c22c903c70b53102fa65e1b8cfdc971f877f1`; first observer source `8a2010d8a6033201d6efd742134dae9f3d235632`. Production routing remains byte-identical to released715036e. The separately verified Arrange-reset candidate is on its own branch. Gitea publication is blocked by the recorded remote disk-full/write errors; all new comparison records are local-only at this checkpoint.
## Experiment and complete accounting
The [plan](plan.md) and [independent criteria](criteria.md) were frozen before engine outputs. Use all five existing corpus cases, fixed engine/options and the released Rust router. elkjs0.12.0 supplies node positions only; its paths and label positions are retained diagnostically and never persisted as authored overrides. Current core-estimated label dimensions are supplied, not measured glyph bounds. This cannot rank ELK's complete drawing quality.
| Case | Reset / native / ELK+Rust proper crossings | Reset / native / ELK+Rust shared length | Outcome |
| --- | --- | --- | --- |
| Workshop original | 6 / 7 / unsupported | 1832 / 1467 / unsupported | Native reduces sharing but adds a crossing and area. |
| Workshop folded | 7 / unsupported / unsupported | 1194 / unsupported / unsupported | Old native prototype rejects folding; ELK adapter rejects an undirected connection before engine invocation. |
| Mixed dispatch | 10 / 7 / 1 | 716.39998 / 4228 / 238 | External placement improves several metrics, with wider bounds and incompatible automatic-port assumptions. |
| Mixed, reversed edge IDs | 9 / 7 / 1 | 512.39998 / 4228 / 238 | Same external scalar vector; semantic ID permutation remains recorded. |
| Sparse40 | 94 / 17 / 20 | 1990 / 40522 / 666 | External transfer adds a NoClearPath and unrelated-node penetration. |
Both workshop ELK attempts stop on undirected edge `22c7011d-b559-5df8-aadd-851002904ba0`; neither is an engine failure or a successful compound-layout comparison. Do not infer compound compatibility from the three flat successes. The four supported native prototype cases are deterministic, idempotent and equal to their first results through ten calls, but stability does not establish quality.
For mixed dispatch, external placement reduces bends39→20 and length10618.60→9361.00 versus current Arrange/reset; estimated label collisions remain zero. Drawing area increases1139880→1808460, about59%. The original authored input already had zero proper crossings and only132 shared units, so improvement over Arrange is not improvement over every original quality dimension. Offline schematics show a more continuous sequence and long feedback paths, but no native trace task was performed.
Sparse external placement eliminates the reset control's estimated label/node14, label/label1 and label/stroke31 collisions. However, length increases39660→64223 and area3804920→12840450, about3.37×. Final bounds8735×1470 imply navigation costs that a thumbnail cannot assess. Its20 proper crossings coexist with28 T and7 bend contacts. The native prototype has shared length40522 despite only17 proper crossings. No weighted scalar winner is appropriate.
## Two interface failures and one repaired observer defect
**Automatic ports are part of placement, not fixed input geometry.** All three final Rust node maps exactly match their imported plans, but mixed and reversed mixed each have10 of25 total port positions changed, including7 side changes. Sparse has48 of110 positions changed and32 side changes. All changed positions belong to automatic ports. Maximum discrepancy224 units; these are not rounding differences. All six authored anchored ports in each mixed case remain exact. The engine's FIXED_POS assumptions therefore do not describe the final Rust drawing. This is a placement/projection interface limitation, not loss of stored anchor metadata.
**The sparse penetration is caused before path search.** Edge `flow_45` (`…03347d`) has target top tip(4634,840), requiring an18-unit outward stub at(4634,822). Unrelated Assessment Package occupies x4522..4746,y660..820; core12-unit inflation reaches y832. The mandatory target lead intersects that obstacle, so the sole semantic-port pair is rejected before cheap/grid search. The fallback reports NoClearPath and penetrates159.9998 units of the actual node interior. No search-budget exhaustion is involved.
Raw ELK avoids actual node interiors for this edge, but its10-unit final lead and10-unit obstacle clearance violate the core18/12 geometry contract. A local necessary separation is30 units rather than the observed20; that is not a proof a complete route exists at30, nor permission to blindly enlarge every gap. The [fixed-scene diagnosis](sparse-routing-diagnosis.md) checks every raw segment against all40 nodes and the relevant inflation/endpoint exemptions. It corrects the initial, narrower observation that an uninflated avoidance corridor existed.
**Identity transfer initially normalized stored sizes.** Source8a2010d8 wrote effective projected minima into authored node sizes even for an unchanged plan. Sourcefc5c22c9 preserves stored size when effective size is unchanged and verifies final reprojection against the exact intended map. All five identity imports now equal independently reconstructed reset-only Projects, preserving stored expanded sizes. The eight import metric/geometry objects and final ports remain exactly equal to the first run, so this repair does not hide either interface failure. [Finding and correction](identity-transfer-finding.md).
## Validation and limits
Windows x86_64-pc-windows-gnullvm, Rust1.98.1, LLVM-MinGW20260908, one Cargo job, offline cached dependencies. Both observer source pins built successfully in release mode and passed strict example Clippy. Final commands, from the repository root:
```text
cargo build --release --locked --offline -p oa-core --example auto_layout_probe
cargo clippy --locked --offline -p oa-core --example auto_layout_probe -- -D warnings
target/release/examples/auto_layout_probe.exe --arrange-corpus harness/experiments/routing-independent-20260925/corpus/manifest.json
target/release/examples/auto_layout_probe.exe --import-placement PROJECT_JSON DIAGRAM_UUID PLAN_JSON
```
Plan JSON is `{ "schema":1, "nodes":[{ "id":"UUID", "position":{"x":0,"y":0}, "size":{"width":224,"height":132} }] }`, containing every visible projected placement exactly once. Import does not apply an intermediate Layout. Collapsed compact dimensions must remain exact while stored expanded dimensions stay intact. Hidden descendants follow their nearest visible collapsed ancestor's translation; unrelated omitted nodes remain unchanged. Nonzero hidden translation and nonempty dormant route translation are source-reviewed, not exercised by this corpus's failed compound reference cases.
Five control cases report exact Undo/Redo and source/JSON round trips. Eight successful final imports (five identity and three external) pass policy-aware whole-Project conservation and round-trip checks under independent review: eligible route resets are expected differences, so the raw `authored_routes_exact` flag is intentionally false for mixed cases. These are pure transformation checks, not native GUI/history tests of an integrated external engine. Six meaningful malformed-plan cases reject: missing, duplicate, unknown placement, zero dimension, changed collapsed footprint and final reprojection mismatch from an actually constrained height. An added width1 negative unexpectedly succeeded because that fixture has no such minimum-width constraint; its failed expectation is preserved, not relabeled. A separate height1 case correctly exercises the vertical-port minimum and exits101 with the expected reprojection error.
The first Python supervisor failed on Windows environment key casing before launching a child; corrected run and original failed script/capture remain. Original identity-normalizing run02 remains alongside corrected run03. All successful process stderr is empty; expected negative cases retain their errors. Final Clippy passed. No Linux, full workspace-suite or native readability acceptance is claimed.
The JavaScript adapter's eight synthetic checks cover nested coordinate conversion, shared physical-port reuse and key rejection paths. One fixed ELK run completed three flat cases in roughly307–624ms engine time, with process times roughly595–913ms; both unsupported cases exit before the engine. No timeout occurred. These are single diagnostic timings, not a native responsiveness bound or comparable Rust route-only benchmark.
Independent [transfer audit](transfer-audit.md) checks complete Project differences, route policy, exact node maps, port drift and receipts. The [geometry review](result-review.md) independently matches48 contact/shared-length comparisons and27 flat label collision counts. It confirms the sparse penetration. [Source audit](source-audit.md), [adapter review](adapter-review.md) and parent observations are retained. Actual glyphs, port labels, arrowheads and named trace tasks remain unverified; no adoption follows from these metrics.
## Reproduction and next decision
Frozen corpus manifest SHA256 `a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717`. External adapter accepts `node reference_probe.cjs CASE_NAME NEW_OUTPUT_DIRECTORY SOURCE_JSONL ELK_BUNDLE`. The exact original source JSONL is archived; SHA256 `9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2`. Fetch the pinned official npm elkjs0.12.0 using the recorded preparation helper/metadata and verify bundle SHA256 `1222e44f953ce7746af23801e723708f8e6f436b8b377a6a5fc7552f34a307b3`. Supervise every engine/observer process with the recorded90-second cap. Convert only structurally passing observations to the narrow plan schema, preserving all original results. Machine-specific runner paths in receipts are provenance; use the pinned commit and your own runtime paths.
Stop this configuration comparison. The next bounded work is a placement-compatibility model that evaluates final automatic-port choices and mandatory port leads against inflated obstacles, with explicit undirected/compound policy. First characterize the exact infeasible lead from this scene; then test whether candidate placement can satisfy those constraints without changing authored anchors or routing contracts. Do not pursue search-budget increases, option sweeps or a production engine dependency on the present evidence. Issue32 and the full application objective remain incomplete.
## Evidence archive
[ZIP](evidence/connection-layout-reference-fc5c22c9.zip) and [member manifest](evidence/manifest.json): 250 files, 3887968 bytes, SHA256 `e68628c8558bb9a1104ed4ca0a0ce612bd0522a1cbce0b9d5c7a8092a7dfeb00`. All member bytes, SHA256 and CRC were reread. Includes all failed/corrected attempts, four successful build/lint gates, raw engine/import outputs, independent reviews, source/driver bindings and17 offline geometry images. Binary payloads are excluded; their hashes and official engine retrieval metadata are retained. [Final claim review](final-review.md) and [parent observations](parent-observations.md) define the acceptance limits.
@@ -1,52 +0,0 @@
"""Bound each frozen reference case in a separate process and preserve all outcomes."""
from pathlib import Path
import datetime, hashlib, json, subprocess, sys, time
local = Path(__file__).resolve().parent
root = local / 'elk-reference-20260925'
node = Path('C:/Users/User/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin/node.exe')
script = root / 'reference_probe.cjs'
source = local / 'routing-corpus-runs-20260925/geometry-released/stdout.jsonl'
manifest = local / 'auto-layout-20260925/harness/experiments/routing-independent-20260925/corpus/manifest.json'
output = root / sys.argv[1]
assert output.parent == root and output.name == sys.argv[1]
output.mkdir(exist_ok=False)
def record(path):
return {'path':str(path), 'bytes':path.stat().st_size,
'sha256':hashlib.sha256(path.read_bytes()).hexdigest()}
bound = [node, script, source, manifest, root/'lib/elk.bundled.js', root/'dependency-receipt.json',
local/'connection-layout-reference-plan-20260925.md', Path(__file__)]
before = [record(p) for p in bound]
assert before[2]['sha256'] == '9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2'
assert before[3]['sha256'] == 'a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717'
assert before[4]['sha256'] == '1222e44f953ce7746af23801e723708f8e6f436b8b377a6a5fc7552f34a307b3'
cases = [c['name'] for c in json.loads(manifest.read_text())['cases']]
receipts = []
for case in cases:
case_output = output / case
stdout = output / (case+'.stdout.log')
stderr = output / (case+'.stderr.log')
argv = [str(node), str(script), case, str(case_output)]
started = datetime.datetime.now(datetime.timezone.utc).isoformat()
start = time.perf_counter()
timed_out = False
with stdout.open('xb') as out, stderr.open('xb') as err:
try:
completed = subprocess.run(argv, cwd=root, stdout=out, stderr=err, timeout=90)
code = completed.returncode
except subprocess.TimeoutExpired:
timed_out = True
code = None
receipt = {'case':case, 'argv':argv, 'started_utc':started,
'elapsed_seconds':time.perf_counter()-start, 'timeout_seconds':90,
'timed_out':timed_out, 'exit_code':code, 'stdout':record(stdout), 'stderr':record(stderr)}
receipts.append(receipt)
(output/(case+'.receipt.json')).write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps(receipt), flush=True)
after = [record(p) for p in bound]
receipt = {'inputs_before':before, 'inputs_after':after, 'inputs_unchanged':before==after,
'cases':receipts, 'scope':'Reference-engine adapter execution; exit0 is not geometry or production acceptance.'}
(output/'receipt.json').write_text(json.dumps(receipt,indent=2)+'\n')
assert before == after, 'Bound inputs changed during experiment'
@@ -1,73 +0,0 @@
# #32 connection-aware placement: source audit and next design
Read-only audit at reset checkout HEAD `956e33e568c6b799d0330803c74927e205977dfd`; line references below are repository-relative at that pin. No source edits, compilation, routing execution or GUI actions. The finished reset behavior is separate from this proposal; neither the old layered prototype nor J/L routing experiments are adopted here.
## What current placement considers—and omits
| Source | Observed behavior | Consequence for #32 |
| --- | --- | --- |
| `crates/oa-core/src/session.rs:970–974` | Children come from the projection-parent forest into vectors in ordered-map traversal order. | Nested siblings remain placement-ID ordered; no internal exchange order or boundary-neighbor order is considered. |
| `session.rs:986–1012` | Port-aware minimum node size, State header/content sizing, then one vertical child column with48 horizontal padding and16 sibling gap; authored size remains a lower bound. | Valid enclosure scaffolding exists, but neither connection demand nor edge label dimensions affect child spacing or container aspect ratio. |
| `session.rs:1017–1040` | Every child starts at parent x+24, stacked beneath the header. | Reversed children in adjacent containers can force intersecting/shared routes even when a sibling permutation would separate them. |
| `session.rs:1052–1070` | Every visible edge is lifted to the two outermost roots; same-root edges disappear; duplicate root pairs collapse into a set. `edge.oriented` is not checked. | Some connectivity is used, but internal demands, multiplicity, ports and labels are discarded. Undirected serialized endpoint order also influences rank-like root ordering. |
| `session.rs:1072–1089` | Choose a remaining root with no remaining predecessor, tie by semantic alias/ID; if none, choose alias/ID anyway. | Deterministic cycle fallback exists, but this is a total topological order, not explicit layers or crossing minimization. |
| `session.rs:1111–1129` | Lay roots left-to-right with240 gaps; wrap after every fourth root with60 row gap. | A seven-node flow is broken into rows regardless of connections. Disconnected graphs and dense bipartite graphs receive the same packing policy. |
| `session.rs:1131–1159` | Apply final placement deltas, existing route translation, and pre-frozen eligible reset. | Useful commit boundary already exists; a better placement planner can replace candidate positions/sizes without redesigning history or route persistence. |
No call inside Layout computes edge-label geometry or scores its proposed final routed result. `routing.rs:1363–1395` derives visible text and estimates label width as7 per scalar plus16, height24; `1410+` tries automatic locations only after paths exist. Therefore source alone confirms that node arrangement is not label-aware. Core estimates must not be advertised as rendered glyph bounds; the independent #36 label work needs explicit reconciliation when integrated.
## Evidence that narrows the choice
The first prototype report, `harness/experiments/auto-layout-20260925/results-01.md` at the separate experiment checkout, documents useful placement effects: reversed children shared length148→0 and label/node collisions1→0; seven-node chain length2560→492 with8→0 bends; long-label collisions2→0. But diamond and bipartite shared strokes worsened. Its nine fixtures omitted folded/filtered topology, Allocation/State, cycles/undirected graphs and genuine other-view conservation. It explicitly rejected omitted/folded nodes, so it cannot be dropped into production Layout.
`harness/experiments/routing-independent-20260925/decision-review.md` retains the released router: J/L pass the finite timing guardrails but expose label and ID-order regressions, and native trace tasks were not met. The next placement experiment should therefore keep the released router fixed. Improving a routing penalty again would obscure whether ordering/space allocation solves the actual placement defect.
## Material alternatives
| Approach | Scope and tradeoff | Decision criterion |
| --- | --- | --- |
| Hierarchical sibling layers and boundary order | Replace vertical/4-per-row packing with connection-informed order, ranks and local corridor sizing, retaining current sizing/transaction machinery. Native Rust and bounded; compound boundary constraints are the real complexity. | Preferred first experiment: improves known nested ordering/label fixtures without corrupting latent folded geometry or worsening named trace tasks. |
| Bounded local improvement of existing positions | Treat current arranged boxes as a baseline; evaluate a small fixed set of sibling swaps, row breaks or gap changes using actual routed results. Preserves more organization and avoids a full layering engine. | Useful control, but reject as primary if it cannot discover the two-container sibling swap without excessive route evaluations or gets trapped by a needed rank change. |
| Compound layout engine adapter | Feed ports, nesting and label rectangles to a mature engine such as ELK via elkjs; validate and commit returned geometry. | Reopen only if native bounded candidates fail concrete compound cases. Additional runtime and mapping cost remain, and the app must still define folded/hidden scope, fixed anchors, measurement and transaction semantics. No engine adoption justified by these results alone. |
These differ in geometry construction/search strategy, not just router coefficients. Do not spend another iteration rebuilding the prototype's known unsupported scope without resolving it.
## Minimal proposed architecture
Keep one pure candidate computation inside the existing core Layout transaction. Inputs are the staged Project, target Diagram, actual projection-parent forest, visible projected connectivity, and deterministic core text-size estimates. Outputs are target-diagram positions/sizes; existing final route translation/reset remains authoritative. Do not call desktop font APIs from core commands or give GUI/API different layouts for identical inputs.
Use two views of the **same** forest: full stored placement ancestry for latent geometry/conservation, and visible connectivity for current arrangement goals. Reuse `projection::parents` (`projection.rs:81+`), which includes Allocation-specific allocation grouping, rather than substituting semantic parent fields. Folded rendering hides descendants and substitutes compact outer heights (`projection.rs:303–335`); that compact footprint is not permission to shrink/delete stored descendants. Preserve descendants' relative geometry when treating a collapsed subtree as one visible box, translating its latent members with the box. This is a proposed improvement over today's rearrangement of hidden descendants and requires an explicit contract choice before implementation. An alternative is retaining today's hidden-descendant reflow with full stored enclosure; it is simpler but may waste visible space. Do not silently mix these policies.
For each sibling group, lift visible edges to the two direct child subtrees at their lowest common ancestor. Use oriented edges for layer direction; undirected edges influence proximity/order only. Keep parallel demands and port-side/order information rather than reducing them to a set. External boundary connections should provide order constraints for the local children too: lifting only at the common ancestor would still miss the reversed-child case. Separate these boundary-order hints from rank constraints to avoid counting one edge as an independent rank demand at every ancestor. Use deterministic SCC handling for cycles, canonical ties, and explicit self-loop space.
Start with a fixed number of sibling order sweeps and one coordinate assignment. Compute container sizes bottom-up from frozen node minima plus content/header/footer/padding, using max constraints instead of repeatedly adding clearance to already enlarged sizes. Reserve corridor width/height using relevant visible label rectangles and edge demand per cut/group, not one global longest label inflated into every gap. Real fixed port anchors are hard constraints; automatic port choices remain derived and must be reprojected after placement, because their side/order and node capacity depend on new peer geometry (`projection/port_layout.rs:156+`). A final reprojection/enclosure check is mandatory before scoring.
Route only a small fixed number of complete candidates with the released router: baseline plus one main layered candidate, optionally one local-swap control. Keep actual path/label metrics and identity-preserving invariants, rather than accepting by straight-line crossing proxies alone. Bound topology preprocessing and routing work globally; on exhaustion return the declared baseline or fail atomically, never partially apply geometry. Selecting a baseline is a fallback outcome, not proof the new layout succeeded. Avoid a weighted scalar that hides new label collisions behind shorter paths.
## Non-negotiable invariants and evaluator changes
- Freeze reset eligibility before placement (`session.rs:955–969`). Route entry/order, attachments and port anchors follow the accepted reset contract; filtered/promoted metadata keeps existing actual-owner translation and State boundary rules. Other diagrams and all semantics remain exact. Generated elbows stay derived.
- Preserve staged Batch semantics and enclosing history. Apply one complete candidate with final validation; no new intermediate validation or hidden history entries. Keep Scenario's existing rejection (`session.rs:950–953`) and do not claim Process support from this work.
- Reuse reset tests in `tests/release_routing.rs:652+`, especially filtered/missing routes792+, folding864+, staged Batch930+. Add independent known-order witnesses for sibling crossing separation, seven-node flow without arbitrary wrapping, local long-label clearance, undirected endpoint reversal, cycle/self-loop, distinct/fixed/shared ports and disconnected components.
- Extend the placement evaluator with the frozen real workshop Allocation views, fold→Arrange→expand, hidden-edge sentinel and untouched other view. Record latent descendants as well as visible nodes; reject node/header penetration and lost port constraints. A visible-only geometry check misses broken expansion.
- Require exact repeat-input determinism and ten-call stability across save/reparse, including periods2 and cumulative container growth. Compare against current baseline and reset-only at the same router pin. Retain pairwise shared intervals, proper/T/bend contacts, label conflicts, warnings, area, route length and workload individually.
- Geometry remains a screen for failures. Parent must verify predeclared connection-tracing tasks and readable labels at normal zoom, then actual Arrange/Undo/Redo/Save/reopen. Current core text estimates and previous offline images do not establish these outcomes.
Recommendation: settle the folded latent-geometry policy, then prototype sibling ordering/layers with boundary hints and local label corridor space. Keep the reset candidate and released router intact until that experiment meets the larger scope. The first milestone is a falsifiable placement result, not a new framework or a claim that #32 is complete.
## Bounded ELK reference comparison: recommended now, dependency decision deferred
An external layout-only reference is feasible and worthwhile before another bespoke placement iteration. This does not contradict deferring a production compound-engine dependency: the comparison buys evidence about ordering and space allocation without committing the application to a JavaScript runtime. Pin elkjs 0.12.0, package integrity, Node executable and adapter/options; retain exact input/output. No ELK execution was performed in this audit.
Verified official capabilities: [ELK Layered](https://eclipse.dev/elk/reference/algorithms/org-eclipse-elk-layered.html) supports ports, labels, compound graphs and cross-hierarchy layout with the appropriate option. [JSON input](https://eclipse.dev/elk/documentation/tooldevelopers/graphdatastructure/jsonformat.html) supports nested children and explicit port references; callers supply label dimensions. [Port constraints](https://eclipse.dev/elk/reference/options/org-eclipse-elk-portConstraints.html) are node-level, including FIXED_POS and FIXED_RATIO. [Coordinate conventions](https://eclipse.dev/elk/documentation/tooldevelopers/graphdatastructure/coordinatesystem.html) default shapes to parent-relative coordinates; recursively flatten returned nodes before transfer. These capabilities do not establish adapter correctness or resulting Rust-route quality.
The frozen geometry rows have sufficient visible inputs: `before.projected_nodes` carries placement IDs, visual_parent, collapsed and allocation_summary; `projected_ports` carries semantic element plus owner placement, side and world position; `projected_edges` carries oriented, source/target placements and optional semantic ports; `routed_edges` supplies existing approximate label dimensions. Full `before_project` supplies authored anchor and dormant geometry records. Use `(owner placement, semantic port)` adapter identities, not semantic element ID alone. Shared ports must remain shared, not be cloned per edge. Use projected ancestry, not semantic parents (Allocation summaries are material here).
Proposed first reference: one fixed Layered configuration, compound hierarchy enabled, explicit direction and seed, fixed visible leaf dimensions, actual header padding for containers, existing label rectangle dimensions. For the initial diagnostic, fixing all imported port positions is an explicit overconstraint: automatic port choices will be recomputed by Rust after placement, and resized containers complicate absolute versus ratio anchors. Keep authored anchor records exact and report final per-port drift from the engine assumptions. Do not persist returned port coordinates to manufacture agreement. A mixed node containing manual and automatic anchors cannot be naively represented by one node-level FREE constraint. Reject unsupported mappings or document the stronger constraint before comparison.
Folded nodes are opaque visible boxes. Their compact projected height must never overwrite stored expanded size. Require planned compact size unchanged, move only their stored position, and translate hidden descendants with the nearest visible collapsed ancestor using full visual ancestry. Other omitted placements remain exact. This is an explicit experiment policy, not automatic adoption of new production folding semantics. Reprojection can enlarge expanded containers or move derived ports; record that difference, since it means the final Rust geometry differs from the engine's output assumptions.
Import only flattened node geometry into the original Project clone, without an initial Layout. Apply the same pre-operation visible/unpromoted actual-owner reset predicate to existing route entries; preserve attachments/order and use original-to-final translation for retained routes. Ignore ELK path sections and label positions. Therefore the result measures ELK-informed placement followed by released Rust routing, not full ELK routing quality; labels reserved by ELK may still collide when the Rust router selects different corridors.
Compare raw authored input, existing Layout/reset control, old layered candidate (unsupported rows explicit), and ELK placement with equivalent reset scope. Do not rank omitted folded rows as successes. Evaluate complete Project conservation with geometry/reset exceptions, compact and expanded containment, fixed anchors, final projected ports, actual Rust routes/labels, named trace tasks, and ID permutation sensitivity. One frozen-input repeated run establishes deterministic transfer only; repeated arrange/reproject feedback is a separate idempotence check. Reject nonfinite/missing/duplicate/out-of-scope nodes and invalid dimensions before any model mutation. A five-case benchmark can justify the next experiment, not production adoption.
@@ -1,45 +0,0 @@
# Sparse placement / released-router compatibility diagnosis
Read-only arithmetic and source inspection; no routing, compiler, GUI or ELK invocation. Source: research worktree `crates/oa-core/src/routing.rs`, released implementation. Frozen imported scene: `elk-reference-20260925/rust-run02/subsystems_40_sparse-elk/stdout.jsonl`; raw engine output: `run01/subsystems_40_sparse/elk-result.json`.
## Finding
**The raw ELK route is clear of all forty actual node interiors but is not feasible under the core clearance and terminal-stub contract. The recorded NoClearPath is caused before bounded search, not by search exhaustion.** No inference about global engine superiority or a missing grid lane follows from this witness.
Edge `00000000-0000-0000-0000-00000003347d`, flow_45, connects Assessment Decide placement `...030dcf` to Planning Aggregate `...030ddd`. Both are semantic ports, so `endpoints` (routing.rs:387–409) returns one fixed endpoint pair. Source bottom tip is (4120,477), mandatory stub (4120,495). Target top tip is (4634,840), mandatory stub (4634,822). Constants are PORT_STUB18 and CLEARANCE12 (lines14–15).
Assessment Package `...030dd1` occupies [4522,4746]×[660,820]. `edge_obstacles` (662–680) inflates it to [4510,4758]×[648,832]. The target stub is strictly inside this unrelated obstacle. The target lead from y840 to822 intersects its interior over y822..832. `route_edge` (830–840) skips the sole pair because its terminal lead crosses an unrelated inflated obstacle. Both cheap and grid passes therefore skip it; neither search is entered for this edge. No exhausted flag is set. Fallback (898–938) retains the mandatory leads and selects the lesser-obstacle-count L path, yielding the recorded vertical x4634 segment through Assessment Package. Its warning is consequently NoClearPath rather than SearchBudgetExhausted. Increasing search limits or adding candidate axes cannot repair this terminal incompatibility.
All forty nodes have visual_parent=None. There are no ancestor-header exemptions to reconstruct. The original imported full Project has no authored route pins for this edge; this is an automatic route with semantic endpoints.
## Raw ELK witness checked against every node
Recorded points: (4120,477), (4120,498), (4502,498), (4502,830), (4634,830), (4634,840). Independent orthogonal interval tests on every segment and all40 rectangles find zero uninflated node-interior intersections. Applying the core12-unit inflation finds:
| Segment | Core inflated obstacle intersection |
| --- | --- |
| (4120,477)→(4120,498) | Communications Publish `...030dc3`, inflated [3996,4244]×[496,652]; last2 units enter its clearance. Source owner alone is exempt on its lead. |
| (4120,498)→(4502,498) | Same Communications Publish clearance. Actual top508 gives only10-unit separation. |
| (4502,498)→(4502,830) | None. |
| (4502,830)→(4634,830) | Assessment Package inflated bottom832 and Planning Aggregate inflated top828 both obstruct the horizontal tail. Actual gap is only20 units. |
| (4634,830)→(4634,840) | Assessment Package inflated obstacle for y830..832. Target owner alone is exempt on its lead. |
The raw final lead is10 units, less than mandatory18. It also turns inside the target's inflated region; exempting the actual target lead does not exempt the preceding horizontal segment. Source lead21 exceeds18 but proceeds into another node's clearance. Comparisons use strict rectangle interiors with epsilon; distances2 and10 are far from numerical ambiguity. No visual or glyph claim is made.
## Smallest useful next test
First add a focused fixed-semantic-port obstacle fixture to the evaluator/tests, using these exact target/package rectangles. Assert the explicit geometric witness: target stub inside unrelated inflated obstacle, no admissible18-unit lead, NoClearPath with unchanged tips and visible fallback warning. This falsifies the hypothesis that more search alone should solve the scene. A warning/fallback test is characterization, not acceptance of the penetration.
Then test a placement compatibility predicate before routing: every mandatory semantic-port lead must be clear of unrelated inflated rectangles; separately check a departure/arrival corridor outside the endpoint's own inflated rectangle. Report incompatible edge/port/obstacle identities rather than scoring fallback as a successful arrangement. For this top-entry pair with horizontal overlap, necessary vertical separation is at least PORT_STUB+CLEARANCE=30 (currently20), ignoring epsilon. A 30-unit gap only makes the lead geometrically admissible; it does not prove a complete route or label solution. Keep other geometry and port identities fixed in a minimal two/three-node witness to test that boundary, then evaluate any actual placement adjustment on the complete frozen scene with normal reprojection and unchanged released router.
For an ELK adapter experiment, reserve sufficient port-facing separation and check returned placements before transfer. Do not blindly increase a global spacing option and assume it enforces every compound/port constraint. Reject/report failures without changing authored anchors or persisting engine bends. Core-router policy alternatives (shorter adaptive stubs, reduced clearance, alternate port side) would change the contract and are separate decisions, not a lane-search fix.
## Scope and evidence
This explains this specific edge's fallthrough directly from immutable scene geometry and source branches. It does not run or instrument the search. Uninflated raw-path feasibility is narrower than core feasibility. Any corrected importer run must confirm the same node/port coordinates before reusing the conclusion.
- .local/auto-layout-20260925/crates/oa-core/src/routing.rs: SHA256 b377fe80cece3892d64f62ba5e1578d8974eeefc2a317620f343a86f2f257fbd.
- .local/elk-reference-20260925/rust-run02/subsystems_40_sparse-elk/stdout.jsonl: SHA256 37ef8db5a920a50a1ed12eba08913fee810d02226d920fc9018088c9e7b14c3a.
- .local/elk-reference-20260925/run01/subsystems_40_sparse/elk-result.json: SHA256 9763cda98e744040e1f2e9ad63662cf6e699e8fbdc7e77b388d60ab4303a4282.
@@ -1,43 +0,0 @@
# Connection-layout transfer audit — run01 / rust-run02
Independent read-only audit of source `8a2010d8a6033201d6efd742134dae9f3d235632`; no engine, Rust, compiler or GUI rerun. Results are diagnostic, not production adoption.
## Findings requiring qualification/correction
1. **Identity import is not reset-only.** All five plans preserve original positions, but the importer writes projected effective dimensions into stored expanded sizes: 3 placements in workshop original, 2 folded, 10 each mixed, and 40 sparse. Mixed stored height94 becomes effective height132, for example. These are real full-Project differences, not float spelling. The three ELK plans likewise keep original projected dimensions yet normalize stored sizes unnecessarily. Minimum correction: when supplied size equals the original projected size (typed f32), retain original stored size; write size only when the plan actually requests a different projected size. Keep collapsed exact-size admission and verify final reprojected dimensions against the plan. Parent has accepted this correction for a separately recorded Rust rerun; run02 remains the original evidence.
2. **ELK FIXED_POS ports are not faithfully transferred by placement-only import.** Every final projected node position and dimension in the three ELK imports exactly equals the recorded ELK plan. Nevertheless, Rust reselects automatic port sides/slots using the new geometry. Mixed and reversed mixed each have 10/25 materially changed port positions and 7 side changes; sparse has 48/110 changed positions and 32 side changes. Maximum coordinate discrepancy is224 world units. No small rounding-only differences occurred in these comparisons. Six authored anchored ports in each mixed case are exactly equal to ELK world coordinates; all material discrepancies are automatic ports. Thus this experiment evaluates placement followed by the existing projection/router, not preservation of the ELK edge-port geometry or ELK quality.
Eight mixed edges and29 sparse edges touch changed ports. Concrete mixed examples: `flow_01` Sensor B observations (`…01adb1`), `flow_03` Archive incoming observations (`…01adb3`), `flow_04` Validated observations (`…01adb4`), `flow_08` Actuator dispatch (`…01adb8`). Sparse examples: `flow_00` Sensing Acquire to Decode (`…033450`), `flow_01` Sensing Decode to Validate (`…033451`), `flow_03` Sensing Enrich to Aggregate (`…033453`), `flow_05` Sensing Decide to Package (`…033455`). Complete identities/coordinates remain in each imported stdout's `after.projected_ports/projected_edges` and corresponding run01 `placement-observation.json`.
## Preservation and limits
Independently recursively compared full before/after Projects for all eight successful imports and five Arrange outputs. Changes are confined to target-diagram node position/size and the intended mixed authored route reset. Semantic records, other views, placement identity/visibility/anchors, target diagram nongeometry, route entry identity/order and any attachment fields are unchanged. The mixed route (`…01adbd`, reversed `…01adb0`) retains its entry, clears its one authored waypoint and label; it is a visible non-promoted projected edge. Other import fixtures contain no authored routes. Consequently these outputs **do not exercise retained hidden/promoted authored-route translation**, multi-entry ordering, or nonempty authored attachment preservation. Source inspection confirms the importer invokes original-to-final `translated_routes` then resets only the captured eligible set; that is source evidence, not coverage of missing cases.
Folded identity import preserves the collapsed placement's stored expanded size272×600 exactly and has no position changes (including hidden descendants). The deliberate changed compact-size plan fails with the explicit collapsed-size rejection. Nonzero hidden-descendant translation remains unexercised: both workshop ELK attempts fail before engine invocation on undirected edge `22c7011d-b559-5df8-aadd-851002904ba0`. They must not be counted as successful hierarchical ELK transfers.
All eight successful import records report exact JSON and single-source round trips without errors. Five actual Arrange records separately report exact undo/redo, one history entry, second-call stability and before/after source/JSON round trips. The imported candidate is a pure transformation, not a Command/history/native GUI test. Five deliberate malformed plans (missing, duplicate, unknown ID, zero size, changed collapsed size) exit101 with the corresponding admission error; they are expected rejections, not successful imports.
## Evidence bindings
Read back175 recorded file bindings across Rust receipt/capture, excluding live target paths: all SHA256 and byte sizes match. All14 Rust invocations have expected exits and unchanged inputs; successful stderr is empty. Verified run01 successful output hashes; three ELK successes record source and bundle unchanged, while both unsupported workshop attempts remain failed.
- `rust-run02/receipt.json`: `7bd7b5dc2da6e078ab9bbec22671cadcb34f6d56765d533c755d1bfbf0465d44`.
- `rust-run02/capture.json`: `649e2f9f27f0d4283ba3b20ad4a3329b9008aeda3a7e80786ebdb2a91667acd4`.
- Preserved Rust binary: `3d0e5aced282761e89b6a36fdcdc79730029db721580941c7fe0315f4ba29f4c`; build receipt `de5b87f55d2b77a61297727940c9ba83fdf2a02aa807b5c8f33b751547fffef5`. Capture explicitly attributes the binary to immediate exclusive-target capture, not a compiler-exit binary hash.
Paths above are relative to `.local/elk-reference-20260925`. Recommendation: correct avoidable stored-size normalization and repeat only Rust transfer checks under a new pin. Preserve the measured automatic-port divergence as an experiment limitation; do not claim faithful ELK routing/port transfer or adopt it from these results.
## Corrected Rust run03 — identity-size finding closed
Read-only audit of `fc5c22c903c70b53102fa65e1b8cfdc971f877f1`, preserving run02. Independently reconstructed each identity expected Project by retaining the complete original and clearing only the existing eligible mixed route waypoint/label. All five identity outputs equal those full expected Projects exactly. All stored sizes now remain exact, including collapsed expanded sizes. All three ELK imports likewise preserve original stored sizes. Thus the avoidable geometry normalization finding is closed for these cases.
For all eight corresponding imports, complete `before` and `after` metric/geometry objects and `final_projected_ports` equal run02 exactly as parsed JSON. The full Arrange control stdout is byte-identical. Full import stdout is intentionally not byte-identical because corrected after-Project stored dimensions differ. Automatic-port discrepancies therefore remain exactly those measured above; the correction does not solve or obscure them. All eight import round-trip flags remain exact/error-free.
Read back179 run03 receipt/capture file bindings (excluding live target paths): every hash and byte size matched; inputs unchanged. The original14 invocations have expected exits. Added `negative-below-minimum` unexpectedly exits0 and must remain a failed negative-test expectation: its plan specifies width1, height132 for placement `…018705`, and final projection actually is width1, height132 at the requested position. Therefore this case does not demonstrate a reprojection-guard defect; its supposed minimum-width precondition is false. It also does not establish acceptable visual readability for width1. Parent plans a separate height1 case to exercise the real vertical-port minimum; no such result was assumed in this audit.
Run03 receipt SHA256 `aaee622d1c93fbdcbb56a16c411a62b30b4242606004704e660e46af5aaca914`; capture SHA256 `90c2b7810b1b9df1d8a41c19f0dce0c49ba9aa9ef8a25ead89caa909584cc30d`. No execution or source edits by reviewer.
### Corrected minimum-size rejection — final readback
Separately reviewed `rust-height-minimum/receipt.json`, plan and logs under the same fc5c22c9 source/preserved binary (`142e88eefedd57acae17f5ebd5b45a9edf682b9d5e5740ab57d2b2fa1d866e98`). The plan sets height1 on `…018705`; stdout is empty and exit101 stderr explicitly reports `Final Rust projection differs from intended node geometry`. Read back all12 before/after/log hash-and-size bindings successfully; inputs remain unchanged. This exercises the final reprojection rejection for the actual vertical-port capacity constraint. It closes the missing negative-test coverage caused by the wrong width precondition; the original width1 unexpected success remains preserved and is not relabeled. Audit frozen after this readback; no reviewer execution.
@@ -1,47 +0,0 @@
# Bounded placement compatibility design for #32
Recommendation: implement **A's small shared core feasibility seam, then B's bounded separation pass as the first experimental consumer**. This is one practical increment toward a native connection-aware planner, not a new router or a general constraint framework. Keep the released router, automatic-port projection policy and accepted Arrange reset/history contract fixed. C remains a diagnostic reference, not the next production step.
This source-only assessment follows reference2850b915 and the exact sparse diagnosis in `placement-sparse-routing-diagnosis-20260925.md`. No source changes, compiler, router or GUI execution were performed.
## What the source requires
- `routing.rs:387–409` maps actual projected semantic ports to exactly one tip and outward18-unit stub. Explicit non-port attachment preferences also constrain endpoints; otherwise four alternatives exist. `route_diagram_impl:519–541` handles promoted ownership, attachment suppression and existing authored route selection before endpoint generation. A planner must not approximate these choices independently.
- `edge_obstacles:662–680` preserves endpoint-ancestor headers, inflates obstacles by12; `route_edge:830–840` exempts only each lead's own endpoint owner from that lead's collision check. `fast_path:1056–1062` and `grid_path:1153–1159` also reject stubs inside any obstacle. Terminal lead clearance is necessary, not sufficient for complete routing.
- `projection/port_layout.rs:156–245` chooses automatic sides from peer centers, semantic fallback and clear exits, then overrides manual anchors. Lines246+ grow capacity and enclose nodes after freezing side choices for that projection call. Reprojecting a new placement can therefore change automatic side, order and effective node size. Fixed semantic port identity does not mean fixed automatic coordinates.
- The existing `examples/auto_layout_probe/layered.rs:27–83` starts with Layout, rejects folded/omitted topology, resets routes, and uses one global largest label for all gaps. Its three passes use boundary-neighbor order but no final lead-compatibility feedback. It is a useful coordinate-assignment skeleton, not ready for adoption; sparse shared-run regressions remain independent of terminal clearance.
## Alternatives and decision
| Alternative | Benefit | Concrete cost / failure | Decision |
| --- | --- | --- | --- |
| A. Shared core endpoint/lead feasibility, then constraint-aware placement | One authority for projection/attachments/promotions/ancestor obstacles. Planner can reserve actual required space and identify blockers. | A broad public routing API would ossify internals; pure advance spacing cannot predict every automatic-port flip. | Add only a small internal, read-only report reused by routing's lead guard and planner. Combine with actual reprojection. |
| B. Postplacement separation with actual reprojection | Small experiment on existing layered output; fixes the exact sparse gap without importing external routing. Tests whether locally enforcing clearance is useful before restructuring all coordinate assignment. | Arbitrary nudging can destroy layers/containment, oscillate as ports flip, and grow area indefinitely. A duplicate obstacle implementation would drift. | First consumer of A, with fixed sibling order, monotone gap constraints, finite rounds and atomic failure. Do not ship a free-form nudge loop. |
| C. ELK free automatic ports / coupled geometry | May let mature layout select compatible port-facing space; useful reference for quality ceiling. | Rust reselects automatic ports after import; importing ELK port locations would change application semantics or persist derived state. Node-level fixed/free policies complicate mixed authored/automatic anchors. Engine lead spacing differs from core. | Defer as implementation. Optional later diagnostic only if native bounded experiment fails a named case. |
## Small implementation seam
Extract a shared predicate for endpoint-pair lead admissibility and stub containment using the already constructed endpoints/edge obstacles. Routing should call exactly that predicate without changing endpoint order, search costs or fallback. A planner-facing internal report can identify edge, end, actual owner, semantic port or attachment, tip/stub, blocker ID/bounds and which guard failed. It must preserve alternative endpoints: an unconstrained non-port end is not infeasible merely because one of its four sides is blocked. Report a hard incompatibility only when no allowed pair survives. For the first separation consumer, act only on singleton endpoints with a unique unrelated obstacle; leave ambiguous alternatives explicit rather than choosing a new persistent attachment.
Reuse the same effective-route selection (promotion suspends custom attachments; semantic ports take precedence) as routing. Avoid a public serializable constraints model, desktop dependency, whole routed path search or label measurement within this report. A private helper plus thin crate-visible wrapper is enough. For a diagnostic example outside the crate, expose only the narrow report if needed, or run the test inside core instead of making every routing internal public.
## Finite native experiment
1. Preserve the original Project and freeze Arrange reset eligibility. Compute the existing connection-aware sibling order/ranks once, including its explicit cycle fallback; keep released/reset control available for comparison. Do not use repeated Command::Layout inside repair.
2. Project the candidate, obtaining actual automatic ports, projected sizes and obstacles. Obtain the shared incompatibility report. If none, proceed to final routing; this is not yet a quality pass.
3. For an actionable blocker, add a separation inequality to the **existing sibling/rank coordinate assignment**, not an arbitrary node translation. Lift owner and blocker to distinct movable child subtrees under their lowest common visible ancestor; translate whole subtrees, including latent folded geometry. If no distinct movable groups exist, report unsupported constraint. Keep sibling order/orientation fixed. Choose a consistent existing ordering axis; for the exact vertically stacked sparse pair, require owner top >= blocker bottom +30. The30 is this 18-unit outward lead plus12 clearance, not a universal node gap. Prefer a small explicit numerical margin for new placement, leaving router epsilon unchanged.
4. Recompute positions and parent enclosure from frozen minima and accumulated gap requirements. Reproject; side changes or capacity growth generate new constraints. Allow at most four repair rounds and a fixed global constraint/work bound. Never alternate swapping the same siblings or add gaps to already inflated stored sizes. Repeated identical geometry with unresolved constraints, opposite incompatible order constraints, excessive extent or exhausted rounds returns an explicit experimental failure and leaves original untouched. The first finite bound is an experiment limit, not proof of convergence.
5. Route the final candidate once with the released router; reject newly introduced unrelated-node penetrations or NoClearPath. Separately assess existing quality vector and trace tasks against reset control. All metadata reconstruction happens once from original to final deltas; retain existing route entries/order/attachments/port anchors, clear only eligible pins/full labels, and preserve hidden/promoted metadata via accepted translation. Production adoption would apply one candidate through the existing transaction/history path with final validation.
This experiment should first use flat sparse and mixed fixtures plus one nested pair, not silently claim all OA/SA/State layouts. The current layered folded/omitted rejection must remain explicit until the separate full-forest policy is implemented. A repair pass does not resolve the prototype's enormous shared runs: if those persist, do not accept it merely because lead clearance succeeds.
## Finite falsifiers and delivery point
- Exact sparse witness: at20-unit gap the target18-unit stub intersects the unrelated12-inflated obstacle; at30 plus declared placement margin the mandatory lead must clear. All tips/port identities follow final projection; no authored anchor edit or persisted bends.
- Automatic-side flip: moving a peer changes side; feasibility is reevaluated on the changed side. A stale first-projection pass is a failure. Shared semantic port must remain one port for all incident edges.
- Fixed-anchor witness and constrained non-port attachment: keep authored values exact; move geometry or fail. An unconstrained non-port edge with one clear side must not force unnecessary separation for its blocked alternatives.
- Nested obstacle: entire selected child subtree moves, children stay enclosed below headers, other branches and all semantic records remain exact. Folded/filtered cases must either satisfy the declared full-forest policy or return explicit unsupported; no unsupported-as-pass accounting.
- Same input twice must match; ten repeated full Arrange candidates must not accumulate clearance or oscillate. A two-cycle or container growth falsifies the proposed assignment scheme.
- Existing five-case frozen corpus: full conservation, actual projected geometry, warnings and unrelated penetration checks; retain label/crossing/shared-run/area values and original named trace tasks. Required outcome is no new hard routing failure plus at least a concrete connection-tracing improvement on a supported real scene. No scalar quality winner inferred from safety alone.
Stop after the shared seam, sparse/fixed-port tests and one bounded repair candidate are evaluated. If repair needs changing sibling order repeatedly or cannot fix the sparse witness without unacceptable displacement, move the constraints into coordinate assignment/ranking rather than adding more repair iterations. If it fixes terminal compatibility but old layered quality remains poor, next work is connection order/corridor allocation, not router penalty tuning. This yields a runnable, falsifiable increment without committing to an external engine or a general solver.
@@ -1,986 +0,0 @@
{
"schema": 1,
"source_commit": "074051261a0beee1047e2b5624c879deef7813bc",
"archive": {
"file": "placement-clearance-07405126.zip",
"bytes": 3887975,
"sha256": "0589a3d413596eec697bab37934d504b055bcf2ab53a0ccc0248ddc107e4a71c"
},
"members": [
{
"member": "collector/analyze-placement-clearance-20260925.py",
"bytes": 3875,
"sha256": "a52be0f3d79870eb554f52036bea032d72e5e641207a21b05f4f6a0779b32da5"
},
{
"member": "collector/analyze-placement-clearance-v2-20260925.py",
"bytes": 3907,
"sha256": "386225a8216e03a4a629e0dbe75d6cc1543d6cf5a20a5ad386e81621d3d5d4b7"
},
{
"member": "collector/archive-placement-clearance-20260925.py",
"bytes": 2866,
"sha256": "67d1f13a7e089668d45f8de10f6567e8c801ed65367ca20e25a1f82f90181bc1"
},
{
"member": "collector/run-placement-clearance-20260925.py",
"bytes": 4663,
"sha256": "8f4a7b8ad7ad10ef854503cd171068a8b395895dfafb82f1f09961e81bbe8fcd"
},
{
"member": "collector/run-placement-clearance-v2-20260925.py",
"bytes": 4727,
"sha256": "3e2449c87938ed233d68fe8f2db53c97e0b5aaa1ced021dbe7217f782a7e0d98"
},
{
"member": "collector/run-routing-corpus-check-20260925.py",
"bytes": 2793,
"sha256": "2726a397bd4ecb4dcfff6fc170a66ce2655229079f42335faa2a4bfe4a202f6d"
},
{
"member": "gates/13-clearance-core-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/13-clearance-core-tests/command/context.json",
"bytes": 3614,
"sha256": "17b422a15ea082957859136d11d2cabe19fdbd66e9d7f1a6143fd104870a1a5f"
},
{
"member": "gates/13-clearance-core-tests/command/inputs-after.json",
"bytes": 1750859,
"sha256": "f0483f2f9ce586c5dafd6e4639dc59116f21c180599a3aa14305b0029c5d7970"
},
{
"member": "gates/13-clearance-core-tests/command/inputs-before.json",
"bytes": 1750859,
"sha256": "f0483f2f9ce586c5dafd6e4639dc59116f21c180599a3aa14305b0029c5d7970"
},
{
"member": "gates/13-clearance-core-tests/command/output.log",
"bytes": 1951,
"sha256": "aa86ca8b741212dabdec034e5b5d2a6ff42bc34669d4cbc395037a487d422dbc"
},
{
"member": "gates/13-clearance-core-tests/command/result.json",
"bytes": 4286,
"sha256": "5fff01d5334d11f96cb035fc74567c156f7397d65d63738d0331e79a1d17b818"
},
{
"member": "gates/13-clearance-core-tests/command/stderr.log",
"bytes": 529,
"sha256": "bfdd486b19efdb9dc23e71473ec74f121f9f5c1f8871892acb68b3dd35822c09"
},
{
"member": "gates/13-clearance-core-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/13-clearance-core-tests/orchestration.log",
"bytes": 185,
"sha256": "638a9a0b1aeaa2ca4e016ccd20a5afa62b8d11ff84e9b37c1ac6500996f9b0da"
},
{
"member": "gates/14-clearance-core-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/14-clearance-core-tests/command/context.json",
"bytes": 3614,
"sha256": "e747d3edc3a8e22c412611866ef6a04a340dce9c5dfbf6c45f267b8f3be4c81d"
},
{
"member": "gates/14-clearance-core-tests/command/inputs-after.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/14-clearance-core-tests/command/inputs-before.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/14-clearance-core-tests/command/output.log",
"bytes": 3737,
"sha256": "6fe31a1fb49deaf06acbaf4f4f88a9188ccb132b8cbe72e051113d2d35302ee5"
},
{
"member": "gates/14-clearance-core-tests/command/result.json",
"bytes": 4284,
"sha256": "67e97e872a0e7936239fe3c3557ed04b2d1542854642017113e5dfc88dbe86c5"
},
{
"member": "gates/14-clearance-core-tests/command/stderr.log",
"bytes": 729,
"sha256": "2540d375f541048be3088c1e1bc4e9d6585ac706490d0823ce6d9f600a199ac5"
},
{
"member": "gates/14-clearance-core-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/14-clearance-core-tests/orchestration.log",
"bytes": 183,
"sha256": "7370c8cba21844ca9b00078dba0c7a03830e32161b102715c97825deb77a9395"
},
{
"member": "gates/15-clearance-unit-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/15-clearance-unit-tests/command/context.json",
"bytes": 3521,
"sha256": "384bba6f9aa5b50ffffa29cd73ef2185882cc62bbd53c25e02e4c31293ba1c4a"
},
{
"member": "gates/15-clearance-unit-tests/command/inputs-after.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/15-clearance-unit-tests/command/inputs-before.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/15-clearance-unit-tests/command/output.log",
"bytes": 14004,
"sha256": "e8e8079c8c5f7e7b7083d408d5f9810ebd4697c0365ec4c5312f5e237aa67b60"
},
{
"member": "gates/15-clearance-unit-tests/command/result.json",
"bytes": 4192,
"sha256": "a7e897f626d6adcca2db2ec79e1d4a7764a87c892c7a36bcd0025847877deaf7"
},
{
"member": "gates/15-clearance-unit-tests/command/stderr.log",
"bytes": 463,
"sha256": "f30d41bf925b7ff2169e0e34d3bd287274bba9dc966484290cec202c06e2f240"
},
{
"member": "gates/15-clearance-unit-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/15-clearance-unit-tests/orchestration.log",
"bytes": 183,
"sha256": "5dafd9bd73d6e6714baadf9ffd01cdfa22572a72882d6c6587e531fc4765c50d"
},
{
"member": "gates/16-clearance-release-build/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/16-clearance-release-build/command/context.json",
"bytes": 3536,
"sha256": "5c22dcf46818a8067f3e465725597510c7e29a32db6bfba1a7b7e912f9e57de5"
},
{
"member": "gates/16-clearance-release-build/command/inputs-after.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/16-clearance-release-build/command/inputs-before.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/16-clearance-release-build/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/16-clearance-release-build/command/result.json",
"bytes": 4209,
"sha256": "b2b897fae6648e0b781f660af1bc893d4393015e4603f490a3cba87475bd3c1e"
},
{
"member": "gates/16-clearance-release-build/command/stderr.log",
"bytes": 179,
"sha256": "2e3fa75afc6e2730e915bef139c9cf8d61d48819a4b43b75be8908efddb58cd3"
},
{
"member": "gates/16-clearance-release-build/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"member": "gates/16-clearance-release-build/orchestration.log",
"bytes": 186,
"sha256": "81b845a84ea6596724b39645b2aa13219d5da6ecd90e5f04064223dce6743cb8"
},
{
"member": "gates/17-clearance-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/17-clearance-clippy/command/context.json",
"bytes": 3592,
"sha256": "6ecbef4a4ea2e4d57a9b716815d41755da74689b6c486e6750436ecbaeccd404"
},
{
"member": "gates/17-clearance-clippy/command/inputs-after.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/17-clearance-clippy/command/inputs-before.json",
"bytes": 1750859,
"sha256": "0232386c3fd6ce76cbc2b4919077fffdd1d8a5fe8eda2d04dcae783ee668c9e4"
},
{
"member": "gates/17-clearance-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/17-clearance-clippy/command/result.json",
"bytes": 4251,
"sha256": "8c6c5562c8ac3b4e59152ace8a37a3dea3816655110f29579d7d2a7dbca6d40f"
},
{
"member": "gates/17-clearance-clippy/command/stderr.log",
"bytes": 177,
"sha256": "3d0e09339f91b9c510019c9d7fb5cc71d390f3b9836ac0e730bee6786f50a3d1"
},
{
"member": "gates/17-clearance-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/17-clearance-clippy/orchestration.log",
"bytes": 179,
"sha256": "3ca5c950ae1dc1d682540cb2bf903da48d0de29301706a342f2af55bbc16a92f"
},
{
"member": "reviews/placement-clearance-repair-implementation-20260925.md",
"bytes": 2624,
"sha256": "dc18890b4549945f853681b0098b5bfab6036192533226dd93bf642c164f8d4c"
},
{
"member": "reviews/placement-clearance-result-review-20260925.md",
"bytes": 6741,
"sha256": "a368b5d3d133092723918874ed0dda669109654fe37e712ea6425a1ecac1d1ee"
},
{
"member": "reviews/placement-clearance-source-review-20260925.md",
"bytes": 9543,
"sha256": "4f371bc0d2de1103c1a7dbc8452f7a1ec5b79a4b48e99c04263b7e0fba32eeaa"
},
{
"member": "reviews/placement-compatibility-design-20260925.md",
"bytes": 10304,
"sha256": "6f8359433ee8f13387b1bc722a8f84d22163f9ba6d8cf8bf5ca1387cf4f5b9cd"
},
{
"member": "reviews/run01-seed-audit.json",
"bytes": 22389,
"sha256": "f3785e637284923e87e55243436c2b45a1f101fb059d69d8a71b5f0def8380ea"
},
{
"member": "reviews/run02-independent-audit.json",
"bytes": 14244,
"sha256": "ec5094c81dc4f200ec53d01fb0dca9efd0ce71338922043f5a18a3d409a46c10"
},
{
"member": "run01/analysis-failure.txt",
"bytes": 582,
"sha256": "7395e44bf226f93f27785e65ec33de0767d8dfe2f56e5fac4db392d867c51d28"
},
{
"member": "run01/capture.json",
"bytes": 8525,
"sha256": "b95c23e22dcd31615f4728183d53cc047818fc10efd457635bb4f5360c0da0b8"
},
{
"member": "run01/inputs/mixed_dispatch-elk.json",
"bytes": 33766,
"sha256": "99350ea7c1757859b24f243d45432e9340c8be6cbaee3b888934220563fa5da9"
},
{
"member": "run01/inputs/mixed_dispatch-layered.json",
"bytes": 33771,
"sha256": "66064d986aaaceceaee01eff736a3ab704f2aa7e0c67bd82ce784bd077871c43"
},
{
"member": "run01/inputs/mixed_dispatch-reset.json",
"bytes": 33769,
"sha256": "c67e9c08e67aa20ede33ba212c05d85caae2a81d15987899ab15c3ab7ec850fb"
},
{
"member": "run01/inputs/mixed_dispatch_edge_ids_reversed-elk.json",
"bytes": 33766,
"sha256": "af8e8a61a3679cad342731907bead643417d7ec6e3c2aa6c3829525186e25928"
},
{
"member": "run01/inputs/mixed_dispatch_edge_ids_reversed-layered.json",
"bytes": 33771,
"sha256": "0edcad8dbce628792233c6a4f439d64e559142b503b12ec5de5f2b6f79d69fad"
},
{
"member": "run01/inputs/mixed_dispatch_edge_ids_reversed-reset.json",
"bytes": 33769,
"sha256": "d4e62c1183b9ef9fbf12e2e9a2fccbbe2d7e940138c25a811cc4962da2d7ff9f"
},
{
"member": "run01/inputs/subsystems_40_sparse-elk.json",
"bytes": 128200,
"sha256": "ef47a2d066571c04776e8d77426fb0bb40b6d692559eaac82dad9abe8ce14c5c"
},
{
"member": "run01/inputs/subsystems_40_sparse-layered.json",
"bytes": 128215,
"sha256": "7f44ec2ca16f7dec5bffaea1a994a849adaac051fb225bac780818e862a5b965"
},
{
"member": "run01/inputs/subsystems_40_sparse-reset.json",
"bytes": 128215,
"sha256": "54c00e446376f761146a9182b72f6b011ed92b09cbcd7914b294ba408719d219"
},
{
"member": "run01/inputs/workshop_sa_folded-reset.json",
"bytes": 106571,
"sha256": "9ed3116546363d13a3976e525e8432ef28148c55f92b66fdb2e19232f85c61ae"
},
{
"member": "run01/inputs/workshop_sa_original-layered.json",
"bytes": 106573,
"sha256": "4b8dcfb2cb71a352a39b214675460a6fda0aaf4d3fb058fe90f6831f7b442b76"
},
{
"member": "run01/inputs/workshop_sa_original-reset.json",
"bytes": 106572,
"sha256": "36276b9f623ffc83f379d8c9b9b3b1780342c73048c0a4d957b28d59e69f082e"
},
{
"member": "run01/mixed_dispatch-elk/receipt.json",
"bytes": 1101,
"sha256": "e8c63b05fbe8036c17fe911bfae30165572aca901dc6cca90c917c76fca3a059"
},
{
"member": "run01/mixed_dispatch-elk/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch-elk/stdout.jsonl",
"bytes": 88395,
"sha256": "f0b6b120cd5fcea1b1549cc4b764c888a62604d06cd756e53bf4ddda3630e879"
},
{
"member": "run01/mixed_dispatch-layered/receipt.json",
"bytes": 1118,
"sha256": "9a15482d16d5ac3c869711924229ac2b918d7866fb60178cb21fd62af0e6245a"
},
{
"member": "run01/mixed_dispatch-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch-layered/stdout.jsonl",
"bytes": 97523,
"sha256": "6f74101c039421e334d6e442a943e8d5c0afa7eb3d6fb37ebb9bc33e5a10c681"
},
{
"member": "run01/mixed_dispatch-original/receipt.json",
"bytes": 1149,
"sha256": "09c61e5024a9ca925cb3d70be32e70f66b9bf2f036487922244350c1bed77446"
},
{
"member": "run01/mixed_dispatch-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch-original/stdout.jsonl",
"bytes": 87849,
"sha256": "a4a7735df682483085c7b33426789d6fedabe1a25c8335a66cc2005990f833fc"
},
{
"member": "run01/mixed_dispatch-reset/receipt.json",
"bytes": 1109,
"sha256": "4a2c2f44698f3cd569e41d3536dc2768a90506ce0a56401e4e15a44c6da5723e"
},
{
"member": "run01/mixed_dispatch-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch-reset/stdout.jsonl",
"bytes": 98875,
"sha256": "6b1d267ccbda72b8b2bc53ebba2c6cbb4af37a1d736139a38b74ffddd7cde2d6"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-elk/receipt.json",
"bytes": 1173,
"sha256": "656d800ec85058e5e1b89e55d3499c64670e73ad348a0f2896956e72f4324ba0"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-elk/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-elk/stdout.jsonl",
"bytes": 88397,
"sha256": "432e5dd9d5a48d1f2e24090de51114e6627b971c24684fed11d629b44f2fca9d"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-layered/receipt.json",
"bytes": 1189,
"sha256": "45858adf871952488e94e2ad103786e78c886cad5c4611695625507e00e9a313"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-layered/stdout.jsonl",
"bytes": 97547,
"sha256": "1d0a7e69c88910f378dd83cbd1bc810648c5ede29945b7e95bd9d3c72d4dffd2"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-original/receipt.json",
"bytes": 1221,
"sha256": "800bf1fc798b77f72005fd5d4fe76c9a11a377b7a513518447d6e391f6565e58"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-original/stdout.jsonl",
"bytes": 87410,
"sha256": "384010f91f91255dbb46b993675bc4fb7f77f988df7b7231bf680950ffacdadd"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-reset/receipt.json",
"bytes": 1182,
"sha256": "1d78d262998d4dc8b15c8dfbbc297971a17ad6629f331141c4d6f62242539148"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed-reset/stdout.jsonl",
"bytes": 99029,
"sha256": "fa1c97f5b9da4cc8b7ac301403b00549bf1360d9d3e09c013f7a8e32b46735d3"
},
{
"member": "run01/receipt.json",
"bytes": 37673,
"sha256": "dfd80e78821c794c01a95fb6e8f2a285d51fe6a712e0d99326d09e3c0c80583d"
},
{
"member": "run01/route-control/receipt.json",
"bytes": 1065,
"sha256": "8f07833144e9eb39e335babd65f926892ee1ee04981579dd4831899d5e3e532c"
},
{
"member": "run01/route-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/route-control/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "run01/subsystems_40_sparse-elk/receipt.json",
"bytes": 1126,
"sha256": "018895ce332f1e29dc169942cf33b9567f5d4af22819b2c4a97efb33421cb32b"
},
{
"member": "run01/subsystems_40_sparse-elk/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse-elk/stdout.jsonl",
"bytes": 357601,
"sha256": "ebfd9632d0ea6df9cfbbc8a3511a5566305bf7523c2316d1a4232a717fa3e836"
},
{
"member": "run01/subsystems_40_sparse-layered/receipt.json",
"bytes": 1142,
"sha256": "3947870f761565db0c70f1b2e5a61891f4cd050940d6b283d7e0f2f70be6343c"
},
{
"member": "run01/subsystems_40_sparse-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse-layered/stdout.jsonl",
"bytes": 368843,
"sha256": "f02bcb62a3e7e11cf994b26e8b5cc074aaff0416ceb122830084f72ba752ffc2"
},
{
"member": "run01/subsystems_40_sparse-original/receipt.json",
"bytes": 1174,
"sha256": "8458a002400e58fd0d96d29f0c7851a269bfb5373d7a9032c31d229ac12b6038"
},
{
"member": "run01/subsystems_40_sparse-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse-original/stdout.jsonl",
"bytes": 366821,
"sha256": "0cc35e367e737ad0ea1fdd34088fc9a674766dc01cfc5e9913a1392258cc0780"
},
{
"member": "run01/subsystems_40_sparse-reset/receipt.json",
"bytes": 1134,
"sha256": "f5111d579f1ec28931745655b6bc52f6afff5c454a4d63a50e0c1949398abcf5"
},
{
"member": "run01/subsystems_40_sparse-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse-reset/stdout.jsonl",
"bytes": 435141,
"sha256": "896d90ef5b1ebb92d9c8af1924543f7276ed9cde18f4888f72f4fec0cfc4e90e"
},
{
"member": "run01/workshop_sa_folded-original/receipt.json",
"bytes": 1165,
"sha256": "d28ea27b77a15966b4335af5ab0c8f2785cc34cd359fc4a1540968de1bab215d"
},
{
"member": "run01/workshop_sa_folded-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_folded-original/stdout.jsonl",
"bytes": 95759,
"sha256": "e2266a5fe9334780a0aca2779c7b43daefb65b7317b8568ddb587db176d754e5"
},
{
"member": "run01/workshop_sa_folded-reset/receipt.json",
"bytes": 1126,
"sha256": "8826a3078df460bf8bf0739797f115a8a85851f513e7ce561affc8c36824ca0b"
},
{
"member": "run01/workshop_sa_folded-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_folded-reset/stdout.jsonl",
"bytes": 93205,
"sha256": "4f4f9bf424e92a33cab0cde7b0ce0992b81819b9b2dfcc3c3da2906fd73808e9"
},
{
"member": "run01/workshop_sa_original-layered/receipt.json",
"bytes": 1141,
"sha256": "94ddfa1e3bb49ff730021937385fcb0729861f12292c8957168d62121a96f69b"
},
{
"member": "run01/workshop_sa_original-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_original-layered/stdout.jsonl",
"bytes": 95705,
"sha256": "213f0ce9f8553aa42e07f3b049b0eeb8f8288677afa9b76419e9f2b884bdbfaa"
},
{
"member": "run01/workshop_sa_original-original/receipt.json",
"bytes": 1173,
"sha256": "663087e42eb6dfa3827327dec703474115e87c8b4284bc99a11ec506db83ff6e"
},
{
"member": "run01/workshop_sa_original-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_original-original/stdout.jsonl",
"bytes": 97692,
"sha256": "de792af0b61cefe9dfc5d92f07d9457fba5abbd29cf37af18b7e1c3d712b6a93"
},
{
"member": "run01/workshop_sa_original-reset/receipt.json",
"bytes": 1134,
"sha256": "028abaffbea45b21c53b46753ff6935de709104958571a8d4b4d043440df80a2"
},
{
"member": "run01/workshop_sa_original-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_original-reset/stdout.jsonl",
"bytes": 97045,
"sha256": "94f31323e069aa5bdcb5607294370071fab4ac13563d8f8ab5fa9ddf38822ed8"
},
{
"member": "run02/analysis.json",
"bytes": 20554,
"sha256": "a3441510e8d93dbc2beec36bcbda26c58a4d04b93465e4ada652911bd0cb344a"
},
{
"member": "run02/capture.json",
"bytes": 8528,
"sha256": "6636ae9b791887effa88f0790d683993d610c498073a5f73f1050bfb1d4694d1"
},
{
"member": "run02/inputs/mixed_dispatch-elk.json",
"bytes": 33766,
"sha256": "99350ea7c1757859b24f243d45432e9340c8be6cbaee3b888934220563fa5da9"
},
{
"member": "run02/inputs/mixed_dispatch-layered.json",
"bytes": 33771,
"sha256": "66064d986aaaceceaee01eff736a3ab704f2aa7e0c67bd82ce784bd077871c43"
},
{
"member": "run02/inputs/mixed_dispatch-reset.json",
"bytes": 33769,
"sha256": "c67e9c08e67aa20ede33ba212c05d85caae2a81d15987899ab15c3ab7ec850fb"
},
{
"member": "run02/inputs/mixed_dispatch_edge_ids_reversed-elk.json",
"bytes": 33766,
"sha256": "af8e8a61a3679cad342731907bead643417d7ec6e3c2aa6c3829525186e25928"
},
{
"member": "run02/inputs/mixed_dispatch_edge_ids_reversed-layered.json",
"bytes": 33771,
"sha256": "0edcad8dbce628792233c6a4f439d64e559142b503b12ec5de5f2b6f79d69fad"
},
{
"member": "run02/inputs/mixed_dispatch_edge_ids_reversed-reset.json",
"bytes": 33769,
"sha256": "d4e62c1183b9ef9fbf12e2e9a2fccbbe2d7e940138c25a811cc4962da2d7ff9f"
},
{
"member": "run02/inputs/subsystems_40_sparse-elk.json",
"bytes": 128200,
"sha256": "ef47a2d066571c04776e8d77426fb0bb40b6d692559eaac82dad9abe8ce14c5c"
},
{
"member": "run02/inputs/subsystems_40_sparse-layered.json",
"bytes": 128215,
"sha256": "7f44ec2ca16f7dec5bffaea1a994a849adaac051fb225bac780818e862a5b965"
},
{
"member": "run02/inputs/subsystems_40_sparse-reset.json",
"bytes": 128215,
"sha256": "54c00e446376f761146a9182b72f6b011ed92b09cbcd7914b294ba408719d219"
},
{
"member": "run02/inputs/workshop_sa_folded-reset.json",
"bytes": 106259,
"sha256": "9e920df52394934d23b0a41f6ef9711fd41252a4d5919e0f373839b35487ab49"
},
{
"member": "run02/inputs/workshop_sa_original-layered.json",
"bytes": 106261,
"sha256": "93bd82eceb23e7782519b4c58387c55fbf9618e611c3c14938c2cc32ebbb81e7"
},
{
"member": "run02/inputs/workshop_sa_original-reset.json",
"bytes": 106260,
"sha256": "68ef8ff4ef7bfd1199ae6dbd13039412d022e7f49219fa7c2f81816af9c124d5"
},
{
"member": "run02/mixed_dispatch-elk/receipt.json",
"bytes": 1102,
"sha256": "5473c00e19f59d6d5fa5a33928f9f935f49ff8b8ad502c1aa677717f9210669e"
},
{
"member": "run02/mixed_dispatch-elk/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch-elk/stdout.jsonl",
"bytes": 88395,
"sha256": "f0b6b120cd5fcea1b1549cc4b764c888a62604d06cd756e53bf4ddda3630e879"
},
{
"member": "run02/mixed_dispatch-layered/receipt.json",
"bytes": 1118,
"sha256": "54cd13fb24ae247405dc58f7212da8a30a839b46c3890542049ebb0bdb0df3ab"
},
{
"member": "run02/mixed_dispatch-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch-layered/stdout.jsonl",
"bytes": 97523,
"sha256": "6f74101c039421e334d6e442a943e8d5c0afa7eb3d6fb37ebb9bc33e5a10c681"
},
{
"member": "run02/mixed_dispatch-original/receipt.json",
"bytes": 1150,
"sha256": "e46b48e3e49dc0ccb10372b32a6d369479241e9c009f078bef9f39ff3269c6f9"
},
{
"member": "run02/mixed_dispatch-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch-original/stdout.jsonl",
"bytes": 87849,
"sha256": "a4a7735df682483085c7b33426789d6fedabe1a25c8335a66cc2005990f833fc"
},
{
"member": "run02/mixed_dispatch-reset/receipt.json",
"bytes": 1109,
"sha256": "69451d3930709bd1800ceaa45608f36100ccb2e7685608b77468b3f258cc1180"
},
{
"member": "run02/mixed_dispatch-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch-reset/stdout.jsonl",
"bytes": 98875,
"sha256": "6b1d267ccbda72b8b2bc53ebba2c6cbb4af37a1d736139a38b74ffddd7cde2d6"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-elk/receipt.json",
"bytes": 1173,
"sha256": "ffef9c8dd2d615250c75eeff5f773f9e664cf7a09f96fad7d64877949a6c3e6e"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-elk/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-elk/stdout.jsonl",
"bytes": 88397,
"sha256": "432e5dd9d5a48d1f2e24090de51114e6627b971c24684fed11d629b44f2fca9d"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-layered/receipt.json",
"bytes": 1190,
"sha256": "8b3eaf9b14c96cee74a8bd4d2fe5226e5dfadc8384265260017a197a104f17ad"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-layered/stdout.jsonl",
"bytes": 97547,
"sha256": "1d0a7e69c88910f378dd83cbd1bc810648c5ede29945b7e95bd9d3c72d4dffd2"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-original/receipt.json",
"bytes": 1221,
"sha256": "0b2264c14a252c9dd92e048f77179ee93f2fb874e158e5f736f4d913f3c8f0fd"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-original/stdout.jsonl",
"bytes": 87410,
"sha256": "384010f91f91255dbb46b993675bc4fb7f77f988df7b7231bf680950ffacdadd"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-reset/receipt.json",
"bytes": 1181,
"sha256": "51a0b236a09548c517557a8a6e89e358c13a1d5d621230fcd025b5671cb441a4"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed-reset/stdout.jsonl",
"bytes": 99029,
"sha256": "fa1c97f5b9da4cc8b7ac301403b00549bf1360d9d3e09c013f7a8e32b46735d3"
},
{
"member": "run02/receipt.json",
"bytes": 37682,
"sha256": "ea2eeea0e09d9588a5c1a025c058455fa984f46d17a154f08ec4d328732cc1ee"
},
{
"member": "run02/route-control/receipt.json",
"bytes": 1064,
"sha256": "3021239a337c4c68ad71727d49b74316f21f36797926737c131ddea02bcab64e"
},
{
"member": "run02/route-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/route-control/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "run02/subsystems_40_sparse-elk/receipt.json",
"bytes": 1126,
"sha256": "c1676d9476d3f178e28f483e1274c6f6019b9cbf6863e6fb5c2a68fb317083a8"
},
{
"member": "run02/subsystems_40_sparse-elk/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/subsystems_40_sparse-elk/stdout.jsonl",
"bytes": 357601,
"sha256": "ebfd9632d0ea6df9cfbbc8a3511a5566305bf7523c2316d1a4232a717fa3e836"
},
{
"member": "run02/subsystems_40_sparse-layered/receipt.json",
"bytes": 1142,
"sha256": "10a62ab568ef9b3b1f4e04bf2002cc5df508e1e983db955c5862fbce2b1650e7"
},
{
"member": "run02/subsystems_40_sparse-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/subsystems_40_sparse-layered/stdout.jsonl",
"bytes": 368843,
"sha256": "f02bcb62a3e7e11cf994b26e8b5cc074aaff0416ceb122830084f72ba752ffc2"
},
{
"member": "run02/subsystems_40_sparse-original/receipt.json",
"bytes": 1174,
"sha256": "243a8f870cdcc3ec4e47dbb6cf19a896672bd1a7040db9c301728752b474bc39"
},
{
"member": "run02/subsystems_40_sparse-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/subsystems_40_sparse-original/stdout.jsonl",
"bytes": 366821,
"sha256": "0cc35e367e737ad0ea1fdd34088fc9a674766dc01cfc5e9913a1392258cc0780"
},
{
"member": "run02/subsystems_40_sparse-reset/receipt.json",
"bytes": 1134,
"sha256": "3b80d2939f1afadde3f37048dc4ea79fb0e4b142ec78dd8d9e82fc55b9bbfbbb"
},
{
"member": "run02/subsystems_40_sparse-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/subsystems_40_sparse-reset/stdout.jsonl",
"bytes": 435141,
"sha256": "896d90ef5b1ebb92d9c8af1924543f7276ed9cde18f4888f72f4fec0cfc4e90e"
},
{
"member": "run02/workshop_sa_folded-original/receipt.json",
"bytes": 1166,
"sha256": "596ac22850349c04fe91ac3e9952e565c754659bcde853d479b0949f898ceb74"
},
{
"member": "run02/workshop_sa_folded-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_folded-original/stdout.jsonl",
"bytes": 95759,
"sha256": "e2266a5fe9334780a0aca2779c7b43daefb65b7317b8568ddb587db176d754e5"
},
{
"member": "run02/workshop_sa_folded-reset/receipt.json",
"bytes": 1126,
"sha256": "724482facb67292b3571f49473bb7b031b30b19da5c83dbb6bc6672e97264fc7"
},
{
"member": "run02/workshop_sa_folded-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_folded-reset/stdout.jsonl",
"bytes": 93076,
"sha256": "95d778bbe3dee916e4204afc50e20b6b6f9b73e40589707948b3db3a73680c3d"
},
{
"member": "run02/workshop_sa_original-layered/receipt.json",
"bytes": 1142,
"sha256": "1ef9543b9c6421b5dc55d69157861d2d2e28ee4c0496b17f99fd7d62cc288a30"
},
{
"member": "run02/workshop_sa_original-layered/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_original-layered/stdout.jsonl",
"bytes": 95576,
"sha256": "cdeb01dfcd147f74f9f3f367b1db0ca7cc45721f6ad09d5d6d0a534783c42611"
},
{
"member": "run02/workshop_sa_original-original/receipt.json",
"bytes": 1173,
"sha256": "960c99b78fdfb2d0b7cc6fe912ae4d74195edb9d91bc33206ac1c9f5398e5719"
},
{
"member": "run02/workshop_sa_original-original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_original-original/stdout.jsonl",
"bytes": 97692,
"sha256": "de792af0b61cefe9dfc5d92f07d9457fba5abbd29cf37af18b7e1c3d712b6a93"
},
{
"member": "run02/workshop_sa_original-reset/receipt.json",
"bytes": 1134,
"sha256": "37f8a5fb878e988dfd62641b6df35c0801fe176906c4e5afd8f826cba22a88ee"
},
{
"member": "run02/workshop_sa_original-reset/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_original-reset/stdout.jsonl",
"bytes": 96916,
"sha256": "9940aa16725bb801e97ff2d2abda0256a7ac5ab3d25609c13f684905f213b363"
}
]
}
@@ -1,28 +0,0 @@
# Final clearance evidence and claim review
2026-09-25. Read-only review of `harness/experiments/placement-clearance-20260925/results.md`, the final related `harness/DECISIONS.md` section, run02 analysis/receipt, independent result review, gate receipts/logs and evidence archive. No compiler, routing/repair execution or GUI actions.
**Verdict: no material overclaim, missing failure or unsupported adoption claim found.** Ready for the parent's documentation checkpoint, with local-only publication status retained until an actual successful push/readback. The record correctly separates solving the named mandatory-lead conflict from general layout quality and native usability.
Verified facts:
- Gates14–17 identify tested executable source `074051261a0beee1047e2b5624c879deef7813bc`, exit0, unchanged inputs and no runner failure. Gate14 log counts5+4+13+18=40 integration tests; gate15 counts130 library and2 example tests. Optimized build and strict Clippy success are recorded. No broader-suite claim is made.
- Both runner receipts contain18 completed, non-timeout, exit0 children with unchanged bound inputs and byte-exact released route control. This does not turn unsupported candidate results into successes. Primary run02 analysis accounts for all17 scenes:12 supported and5 workshop-topology refusals.
- Only sparse ELK changes node geometry, moving8 nodes and23 ports with no side changes. The two original mixed scenes change route/bounds metrics through the declared reset without node/port movement; results explicitly avoid attributing that to clearance repair.
- Sparse lead incompatibility, NoClearPath and unrelated-node penetration each change1→0 while overlap remains0. Reported regressions20→22 crossings,55→58 contacts,666→761 shared length and0→1 label/stroke intersection match primary analysis and independent review. The stated outcome does not infer native unreadability or improvement from those metrics alone.
- The independent result review supplies complete Project conservation and port-identity checks beyond the observer's broad booleans, independent raw-contact/penetration arithmetic, and recorded repeat/roundtrip coverage. Documentation keeps automatic side changes, compounds, opposite-order rejection, native tracing and timing guarantees outside the established scope.
- Gate13's invalid primitive DataType fixtures and the corrected Record fixture are explicit. The first runner's cp1252 decoding issue is preserved, with81 altered string leaves across three workshop seeds, no numeric differences, and run02 designated primary. Unsupported topology, previous quality problems, and publication failure are not omitted.
Archive independently read back: `placement-clearance-07405126.zip`,195 members,3887975 bytes, SHA256 `0589a3d413596eec697bab37934d504b055bcf2ab53a0ccc0248ddc107e4a71c`. ZIP CRC test passes and every member's byte count/SHA matches `manifest.json`. Gate13 receipts and both the run01 seed audit and run02 independent audit are present. This confirms the archive integrity claim; it does not add a new execution or usability result. This final review is outside that immutable archive.
One minor wording issue: reproduction says “archived v2 collector” when the intended executable workflow is the v2 experiment runner. The archive collector packages existing evidence. Prefer naming that runner or changing “collector” to “runner”; this is not a correctness blocker.
Independently inspected the subsequent `clearance.rs` diff: only the16-factor work-charge comment changes, with no executable statement changed. The source review already treated it as a weighted budget, not a conservative bound on actual scans/projection work or wall time. Executable gates remain attributed to07405126; document the later comment explicitly rather than claiming a fresh tested source pin.
Reviewed document hashes at inspection (subsequent wording updates may change them):
- results.md: `7ac0155cb52acd2a3b0ba9782c0b7387a3efe19daa0d6a9346e9acae70bd3d7e`.
- result-review.md: `a368b5d3d133092723918874ed0dda669109654fe37e712ea6425a1ecac1d1ee`.
- DECISIONS.md: `5ebc04454e9f736bde41befa9575a06c08c08d3539b5c89fa59b82be05b0860c`.
The no-adoption decision is proportionate: retain released routing and arrangement, keep repair example-only, and use final-port/lead compatibility as a necessary constraint in future initial coordinate assignment. No issue closure, production integration, Linux verification or remote publication is established here.
@@ -1,11 +0,0 @@
# Bounded flat clearance repair candidate
Own module: `crates/oa-core/examples/auto_layout_probe/clearance.rs` in research worktree. Pure `repair(&Project, Id) -> Result<Project, ModelError>`; no compilation/execution by implementation agent. Parent owns CLI, test execution, final original-to-final route metadata reconstruction, and integration. Input routes, authored sizes/anchors and semantic records are untouched by this function.
Freeze total X/Y orders by initial coordinate then placement ID. Reject initial actual-node overlaps. For every disjoint pair, retain its original gap on one existing separating axis (deterministic X before Y); preserve adjacent start order on both axes. For a diagnosed singleton blocked lead, strengthen the corresponding outward-facing owner/blocker boundary separation to PORT_STUB + CLEARANCE + explicit1-unit margin, currently31. Reject ambiguous endpoint sets, noncardinal blocked leads and constraints opposing frozen order. Solve acyclic longest-path lower bounds from frozen initial coordinates, so movement is positive and constraints only strengthen.
Reproject after each adjustment and before success: identity/topology and every effective node size must remain unchanged. Diagnostic uses actual reselected automatic ports, not frozen engine ports. Four adjustments maximum; unresolved or non-strengthenable failures reject. Bound256nodes/1024edges,100000-unit span per axis, and10000000 charged work units (including conservative16 endpoint-pair/node allowance per diagnostic round). Nested/folded/omitted/Scenario input is rejected. Errors drop a private clone and cannot mutate the input.
This is deliberately conservative: fixed-axis pair gaps may propagate movement farther than necessary; opposite side changes may make constraints impossible under the frozen order. Size-changing automatic capacity redistribution is rejected rather than silently accommodated. Work accounting bounds explicit pair/constraint/diagnostic scan allowance, not wall-clock time or all projection internals. Empty lead incompatibilities prove only the router's necessary lead guard, not obstacle-free complete paths, label clearance, readability or adoption. No heuristic nudges, engine tuning or production changes are included.
API inspected: routing::lead_incompatibilities(Project, Diagram, ProjectedView) returns actual singleton candidates and inflated blocker identities. Stub containment is diagnostic-only and is not substituted for the existing lead guard. Parent should retain all rejected cases and evaluate full route/label results independently after successful repair.
@@ -1,43 +0,0 @@
# Placement clearance experiment
Continuation of issue32 from connection-layout-reference results at2850b915.
The sparse external placement leaves20 units between rectangles where its
final Rust top port needs18 units of outward lead plus12 units of unrelated
obstacle clearance. This experiment addresses that necessary placement
condition. It does not adopt either previous placement candidate.
Use the router's actual endpoint selection, promotion/attachment policy and
lead collision predicate in a narrow read-only diagnostic. Preserve existing
router guard order, search, costs and fallback. Compare the five-case frozen
route output exactly with the released-router control, and exercise targeted
lead, alternative-endpoint and folded/ancestor tests.
First consumer is an isolated example-only flat repair: at most256 nodes,
1024 edges and four separation rounds. Freeze axis order and initial coordinate
floors; seed separation inequalities from every initially disjoint node pair.
Add a31-unit boundary gap (18+12+1 margin) for unambiguous cardinal singleton
lead blockers and recompute monotone coordinates. Reproject actual automatic
ports each round. Reject overlapping input, unsupported nested/folded/omitted
topology, conflicting order, projection size changes, excessive extent/work,
or unresolved constraints. No mutation escapes on failure. This narrower
first experiment deliberately leaves subtree/compound coordinate assignment
for a later planner increment.
Evaluate all five frozen original and Arrange-reset scenes, all four supported
old native candidates, and all three prior ELK geometry transfers, unchanged.
Keep unsupported cases and failures explicit. Reconstruct route reset/retained
translation once from input to final geometry using the audited import helper.
Check semantic/anchor/other-view conservation, round trips, repeat determinism
and ten repeated repair calls. Report all existing quality measures, actual
port changes, warnings and unrelated-node penetrations. Require the exact sparse
terminal conflict to disappear without introducing a new node overlap or routing
failure before calling this compatibility increment successful. Lead clearance
alone is not complete routability or readability acceptance.
Stop after one bounded candidate and independent review. If the sparse witness
cannot be repaired under frozen orders, retain the counterexample and move
constraints into initial coordinate assignment; do not increase iteration
counts or tune the corpus. Even success leaves prior shared-run, area,
compound/undirected and native usability limitations unresolved.
Windows only. No Linux build, release change or production Arrange adoption.
@@ -1,57 +0,0 @@
# Independent clearance experiment result review
Primary evidence is explicit-UTF8 `placement-clearance-20260925/run02`, source074051261a0beee1047e2b5624c879deef7813bc. Read-only analysis of recorded Projects/geometry/receipts; no compiler, router, engine or GUI run. **The bounded repair resolves the exact sparse terminal incompatibility, but the result is not a general connection-aware Arrange solution or a quality winner.** It remains flat-only and worsens several tracing metrics.
## Admission and corpus integrity
Independently verified every run02 bound input's current SHA against inputs_after, exact inputs_before/after equality, all18 process receipts (17 candidate cases plus routing control) exit0/not timed out, and stdout/stderr hashes. Routing-control bytes equal the frozen released-router geometry file for all five original cases. These observations support the narrow no-output-change routing refactor claim for that corpus, not all possible graphs.
All12 generated seed Projects exactly equal the corresponding prior UTF8-decoded Projects, recursively without float tolerance. Original corpus files remain hash bound. Run01 is preserved and superseded: nine generated mixed/sparse seeds were exact, but three workshop seeds each changed27 string leaves (81 total). Every change is exactly the result of decoding original UTF8 bytes as cp1252; numeric geometry and structure were unchanged. Full paths and values are in `placement-clearance-run01-seed-audit-20260925.json`. Corrected run02 removes those seed changes. This is runner encoding failure, not model mutation by the Rust candidate.
## All17 cases accounted for
- Unsupported5: workshop original's original/reset/layered placements, and folded workshop original/reset. Each explicitly reports nested/folded/omitted placements unsupported. No successful hierarchy result is inferred.
- Supported12: four original/reset/layered/ELK placements for each of mixed dispatch, its relation-ID permutation, and sparse40.
- Eleven supported cases have no node movement. Sparse40 ELK alone moves8 stored node positions by exactly(0,+11), changes23 projected port positions and zero port sides.
For every supported case, independently reconstructed the entire expected raw Project from before: substitute only returned node positions and clear waypoints/full label only for visible flat edge route entries. Complete object equality with after proves preserved stored sizes, all node metadata/anchors, semantic records, other diagrams, route entry/order/attachments and unrelated fields. Verified exact stored/projected node identity scope, flat/unfolded topology, complete `(owner,element)` port key sets without duplicates, and exact projected-edge identities/semantics. This does not rely on the emitted conservation booleans. All12 recorded same-input repeats and9 subsequent repair calls report exact equality; both recorded JSON and source roundtrips are exact. These are assertions from the frozen executable output, not independently rerun commands.
## Independent geometry agreement
Applied the preexisting independent segment interval/contact evaluator to all24 before/after supported scenes. All96 comparisons agree within0.001 for proper crossings, unique pairwise contacts, common physical terminal contacts and raw pairwise shared length. Independently intersected every unrelated routed stroke with flat node interiors and every node pair in all24 scenes; penetration and overlap counts agree. Full results and source receipt binding are retained in `placement-clearance-run02-independent-audit-20260925.json`.
Sparse ELK changes:
| Metric | Before | After |
| --- | ---: | ---: |
| NoClearPath warnings |1|0|
| Unrelated node penetrations |1|0|
| Unrelated node overlaps |0|0|
| Proper crossings |20|22|
| Point contacts |55|58|
| Pairwise shared length |666|761|
| Label/stroke intersections |0|1|
| Total route length |64223|64322|
| Drawing area |12840450|12936535|
The shared/crossing/contact/penetration numbers above have independent arithmetic corroboration. Label/stroke, length and area are emitted metric observations; the new label/stroke witness is explicitly identified below. No count establishes glyph readability or navigation usability.
## Exact repaired witness
Assessment Package remains x4522..4746,y660..820. Planning Aggregate moves from top840 to851 with unchanged stored/projected size224×160. Its top port is now(4634,851), outward18-unit stub(4634,833). The blocker inflation ends at832: the planned one-unit margin is realized exactly. Independently checked all110 semantic-port terminal leads in the final sparse scene against all40 inflated rectangles: zero unrelated lead intersections and zero stub-containing obstacles.
Flow_45 `...03347d` now follows (4120,477)→(4120,495)→(4377,495)→(4377,833)→(4634,833)→(4634,851). The recorded prior160-unit unrelated-node penetration is absent under independent interval tests. This validates the local spacing hypothesis without changing port sides, authored anchors, or adopting raw ELK bends.
A new recorded label/stroke intersection remains: flow_45 crosses the label of edge `...03347a`, emitted interior intersection length23.9998. Thus the former hard terminal failure has been traded for additional route contacts/crossings/sharing and a new label interference. The test is a useful capability witness, not adoption evidence.
## Decision and limitations
Accept the evidence that final-projection lead compatibility is a useful placement constraint and that this bounded flat repair can solve the named mismatch. Do not adopt the repair as the user-facing Arrange planner: five hierarchy cases are unsupported, supported no-op cases retain their prior quality limitations, and sparse quality is non-dominating. Do not retune this frozen experiment to erase the tradeoff. The next implementation decision belongs in connection-aware placement/coordinate assignment with shared lead constraints and actual reprojection; production selection/history integration and native trace tasks remain untested here.
The diagnostic is necessary-only, and the independent final sparse clearance check does not imply every graph admits a route. No performance, glyph measurement, native usability, production acceptance or remote publication claim is made.
- placement-clearance-run02-independent-audit-20260925.json SHA256 ec5094c81dc4f200ec53d01fb0dca9efd0ce71338922043f5a18a3d409a46c10.
- placement-clearance-run01-seed-audit-20260925.json SHA256 f3785e637284923e87e55243436c2b45a1f101fb059d69d8a71b5f0def8380ea.
- receipt.json SHA256 ea2eeea0e09d9588a5c1a025c058455fa984f46d17a154f08ec4d328732cc1ee.
@@ -1,124 +0,0 @@
# Mandatory-lead placement repair result
**The diagnosed sparse terminal conflict is repairable with a bounded native
separation pass, but the result is not an accepted Arrange replacement.** It
removes the routing warning and unrelated-node penetration while making
crossings, shared connector length and one label/stroke intersection worse.
Keep the released router and production node arrangement. The next useful
planner work is connection ordering and corridor/label space during initial
coordinate assignment, including compound geometry; do not add more local
repair rounds or retune router penalties on this corpus.
Source `074051261a0beee1047e2b5624c879deef7813bc`, based on the placement reference
at2850b915. Core changes extract the existing endpoint choice and early lead
guard into shared helpers and expose a read-only necessary-condition report.
Router search/cost/fallback behavior is unchanged. Repair is an example-only
consumer, unsupported for nested/folded/omitted placements and Scenario.
It is not connected to Command::Layout, REST or desktop history.
## Observed result
Primary run02 preserves the five original scenes, five Arrange-reset controls,
four old native candidates and three external-placement transfers. Twelve flat
cases are supported; the five workshop variants explicitly reject unsupported
topology. These are not counted as repair passes. Only the sparse external
placement changes node geometry: eight nodes move down11 units. Twenty-three
of110 projected port positions move, with zero side changes. Final port
identity and owner sets are exact.
The target Planning Aggregate top moves840→851 while Assessment Package's
bottom remains820. The top port's18-unit outward stub ends at833, just beyond
the inflated blocker bottom832. The sole incompatible edge becomes admissible
and obtains a complete route with no warning or unrelated-node penetration.
| Sparse external placement measure | Before | After repair |
| --- | ---: | ---: |
| Incompatible mandatory-lead edges | 1 | 0 |
| NoClearPath warnings | 1 | 0 |
| Unrelated-node penetrations | 1 | 0 |
| Node overlaps | 0 | 0 |
| Proper crossings | 20 | 22 |
| All point contacts | 55 | 58 |
| Pairwise collinear shared length | 666 | 761 |
| Label/node and label/label collisions | 0 / 0 | 0 / 0 |
| Label/stroke intersections | 0 | 1 |
| Route length | 64223 | 64322 |
| Drawing area | 12840450 | 12936535 |
The two original mixed scenes also change route length and drawing bounds because
eligible authored pins/label overrides are reset; no nodes or ports move.
Do not attribute that effect to the new separation pass. All other supported
cases retain geometry and measured results. The old native sparse candidate's
40522 shared-length problem remains. Empty lead diagnostics do not establish
legibility or complete route feasibility.
All12 supported outputs conserve the complete Project except declared node
positions and eligible route reset, retain stored node sizes and port anchors,
preserve complete projected edge/port identity, and pass JSON/single-source
round trips. Duplicate input gives the same result; all nine subsequent calls
through call10 remain exactly equal. Automatic side-flip repair, compound
translation, opposite-order rejection and native usability are not established
by these successful corpus cases.
## Verification and failures retained
Windows Rust1.98.1 gnullvm, LLVM-mingw20260908, offline locked dependencies,
one build job and previously frozen environment. No Linux build or native UI
acceptance run for this experimental repair.
The subsequent evidence commit changes only a prototype budget comment and
documentation/evidence; executable Rust statements remain those tested at07405126.
```
cargo test --locked --offline -p oa-core --test lead_feasibility --test routing_geometry --test edge_attachments --test port_anchors
cargo test --locked --offline -p oa-core --lib --example auto_layout_probe
cargo build --release --locked --offline -p oa-core --example auto_layout_probe
cargo clippy --locked --offline -p oa-core --lib --example auto_layout_probe --test lead_feasibility -- -D warnings
```
Gates14–17 pass at07405126:40 selected integration tests,130 library tests,
2 example solver tests, optimized build and strict Clippy. No broader-suite
claim. Five-case route-control JSONL is byte-for-byte identical to the frozen
released-router output (SHA2569a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2).
Both runners complete18 children (route control plus17 scenes), exit0 with
unchanged bound inputs; unsupported status is inside the result, not inferred
from exit status. Each child has a90-second cap. No latency claim is made.
Gate13 at2be8c7f2 compiled but two new non-port fixtures failed semantic
validation because their default DataTypes were primitives. Source07405126
changes only those fixtures to valid Record types; the failed receipt remains.
The first analysis failed on implicit Windows cp1252 decoding of UTF-8 JSONL.
Independent audit found81 altered string leaves in three workshop seeds
(27 each), no numeric/geometry differences; nine other generated seeds were
exact. Preserve run01 as superseded evidence. The v2 runner/analyzer use
explicit UTF-8 and produce primary run02. They also independently compare the
complete raw Project modulo allowed changes and full(owner,port) identity sets.
The prototype's work counter is a weighted size/iteration budget, not an exact
count of all routing/projection operations or a wall-clock guarantee. Explicit
graph, round and span limits remain separate guards.
## Reproduction and evidence
Build the source pin above, then use the archived v2 experiment runner with the frozen
corpus and prior reference archive. The portable probe interface is:
```
auto_layout_probe --route-corpus MANIFEST
auto_layout_probe --repair-placement PROJECT_JSON DIAGRAM_UUID
```
The latter emits before/after geometry, full models, diagnostics, quality
measures, metadata checks and ten-call stability. Original inputs, run receipts,
commands, scripts, failure logs and independent audits are retained in
`evidence/placement-clearance-07405126.zip`; `evidence/manifest.json` identifies
every member and SHA256. Native binaries are represented by capture hashes,
not embedded. See [source review](source-review.md), [result review](result-review.md),
[final claim/archive review](final-review.md), [design alternatives](design.md)
and [bounded consumer](implementation.md). The final review is versioned outside
the immutable evidence archive; its minor runner wording correction is applied.
This branch evidence is local-only until a successful Gitea push and byte
readback; earlier publication attempts failed with remote disk-full errors.
No issue closure, release change, merge or whole-Arrange quality claim.
@@ -1,51 +0,0 @@
# Independent placement-clearance source review
2026-09-25. Reviewed the initial working diff and then its settled, clean commit `2be8c7f2929684a99bfb92b63e1585980d6313cf` against `2850b915`, including the plan, routing extraction, diagnostic, flat repair, tests and example CLI. No edits, compilation, test execution, routing calls or GUI actions by this reviewer.
**Verdict: no P1/P2 source blocker found for the declared bounded experiment.** The extracted predicates appear behavior-preserving, and the flat repair's separation constraints preserve an initially disjoint axis for every node pair. Approval here is for verification of this candidate, not production adoption or a claim that lead clearance establishes routability. Parent's exact frozen-route comparison and17-case experiment remain necessary.
## Findings and verification limits
**P3 — semantic/coincident self-loop coverage is narrower than the requested diagnostic coverage.** `crates/oa-core/src/routing/leads.rs:142` verifies the coincident exception and owner-obstacle distinction using direct helper calls. It does not run `lead_incompatibilities` on an actual projected semantic self-loop or coincident authored attachment pair. The source reuses the real endpoint selector and reproduces the route-edge coincident condition, so this is a coverage gap, not an identified false result. If the parent claims these cases tested, add or reuse an actual Project/projection-level witness; otherwise preserve the limitation. Existing self-loop routing tests can establish routing regression coverage but not every new report field.
**P3 — solver unit tests do not establish full repair/persistence behavior.** `crates/oa-core/examples/auto_layout_probe/clearance.rs:260` and `:274` exercise one propagated inequality and an extent refusal. The17-case observer must verify final no-overlap identities, the exact sparse lead/warning/penetration changes, complete metadata/reset policy, and ten-call stability. Its emitted `supported:true` only means the repair/import returned successfully; no quality-pass follows. A duplicate-call failure currently appears as `same_input_exact:false` without its error text, sufficient to fail repeatability but less diagnostic than the ten-call error record.
No source change is requested solely to broaden this first experiment. Failed cases and the above limits must remain explicit in the report.
## Router extraction
At `routing.rs:425`, `effective_route` retains actual-owner versus projected-owner promotion, suspension of the whole authored route when promoted, and semantic-port precedence over dormant explicit attachments. At `:447`, `edge_endpoints` calls the previous `endpoints` expressions in source/target order with the same semantic/projected-port fallback. These helpers are pure reads; source/target endpoint vectors have the same ordering.
At `routing.rs:475` and `:483`, the allowed-pair and mandatory-lead expressions are the original expressions with the same Boolean logic. The route path still filters self-loop anchors before candidate scoring/sorting, and still checks the lead guard after best-cost pruning at `:868`. Pins, obstacle construction, preview reuse, search budget, costs and fallback are not changed by this extraction. Moving the two endpoint calls into a local array before `route_edge` does not introduce a mutation or reorder obstacle/pin processing. This is source-equivalence reasoning; only the pending recorded-route equality check establishes observed unchanged output.
## Diagnostic fidelity
`routing/leads.rs:67` constructs the same node/rectangle/header maps and edge-ID order as the router. It uses effective promotion/attachment policy, actual endpoint alternatives and `edge_obstacles`, including ancestor-header versus traversable-body treatment. Missing projected owners are skipped as in routing; empty diagnostics cannot certify that all semantic connections are present.
The diagnostic counts every permitted source/target pair and reports an incompatibility only when none passes the exact early lead guard (`:100–118`). It therefore does not promote one blocked automatic side to a hard incompatibility when another side remains usable. Coincident singleton tips use the same exception as route-edge selection. Pins, later stub-search containment, path reachability, global search budget and labels are deliberately outside this necessary-condition diagnostic.
`describe` at `leads.rs:43` excludes an endpoint's own rectangle from lead blockers, matching the early guard. `stub_containers` deliberately includes all containing obstacles and is separately documented; consuming it as additional mandatory blockers would change the historical semantics. The repair correctly uses only `blockers`.
The integration tests meaningfully distinguish20-unit blocked clearance from30/31-unit clear geometry, assert independent tip/stub/inflated-obstacle coordinates, check read-only Project equality, semantic-port precedence over stored attachments, and an unconstrained alternative versus explicitly anchored non-port endpoint. The ancestor/promotion test at `lead_feasibility.rs:182` is transparently a synthetic projected forest; it proves that supplied-view policy, not a complete authored folded-project lifecycle.
## Monotone flat repair
`clearance.rs:130` seeds one boundary inequality for every initially disjoint pair: X separation when available, otherwise Y. Initially overlapping rectangles are explicitly refused. Because positive extents make each chosen direction forward in that axis's frozen start-coordinate order, these original constraints are acyclic. Newly required lead gaps are accepted only in that same rank direction (`:214`).
`solve` at `:27` visits targets in frozen order, so every constraint predecessor has already been resolved. It applies coordinate floors, nondecreasing adjacent starts, and `start[to] >= start[from] + extent[from] + gap`. Constraints only strengthen and dimensions are rechecked each round. Therefore, in the represented arithmetic, each pair retains at least its originally selected separating axis; strengthening a lead gap cannot remove that preserved pairwise separation. The recorded final overlap check remains appropriate for f32 effects and integration mistakes.
The31-unit required gap is `PORT_STUB + CLEARANCE +1` at `:217`; it is deliberately conservative for a flat rectangular blocker in front of a cardinal singleton endpoint. Unexpected direction, degenerate lead, multiple endpoint choices, unknown owner/blocker or a constraint opposing frozen order returns an error. Reprojection after every adjustment observes automatic-port changes; it does not assume the initial tips remain attached to the same side. Up to four adjustments are allowed, followed by a final diagnosis; a still-blocked or unstrengthenable result fails explicitly.
Flat, complete, noncollapsed topology, finite positive geometry,256 nodes,1024 edges,100000-unit span and a cumulative work allowance are checked. There is no unbounded iterative optimizer. The work allowance is a coarse charge for bounded graph operations, not an exact CPU-operation counter or wall-clock guarantee; parent process supervision remains useful. Every failure drops the private clone.
## Metadata and interpretation boundary
`clearance::repair` changes only positions in its clone. It does not incrementally rewrite stored routes or anchors while adjusting. Parent wrapper `auto_layout_probe.rs:1027` invokes the audited import policy once from the original input to final projected geometry. That preserves authored sizes when projection minima are unchanged, actual attachments and other-view records; applies retained-route translation from the full final deltas; and clears only original eligible pins/full labels.
Even if no node movement was needed, the wrapper can still clear eligible pins/labels. Thus output differences on an original authored scene may include the declared reset, not solely clearance movement. Compare complete records and the appropriate reset control before attributing quality gains to gap repair. For scenes already reset this distinction disappears.
CLI results expose baseline/final geometry, lead reports, conservation, roundtrip, same-input equality and repeated repair outcomes, with explicit errors for unsupported cases. The accepted success criterion remains the plan's narrow one: remove the exact sparse terminal conflict without a new node overlap or routing failure. Empty lead reports alone cannot establish this, and even that compatibility result leaves shared runs, labels, area, compounds and native traceability unresolved.
## Fixture correction addendum
Reviewed parent follow-up `074051261a0beee1047e2b5624c879deef7813bc`: only five fixture lines change, converting the three DataType definitions to `Record { supertype: None }` before constructing the DataAssociation. The previous fixture relied on the default primitive definition, contrary to `crates/oa-core/src/data.rs:1089` requiring Record endpoints. The original gate13 failure remains evidence of a fixture precondition defect, not a passing non-port test. This correction supplies valid intended association endpoints without changing geometry, assertions, production routing, diagnostic or repair logic. Test functions now start at107/144/167/187; earlier test line references refer to2be8c7f2. No rerun result is claimed here; gate14 is parent-owned. Static verdict is unchanged, now covering this exact correction.
@@ -1 +0,0 @@
* -text
@@ -1,64 +0,0 @@
# Independent routing corpus: pre-result adoption rubric
Prepared before the new corpus routing/timing outputs. This is a proposed engineering decision rule, not a replacement for user requirements or a production acceptance claim. Compare released715 router, J and L on identical frozen cases; route-only observation must not invoke the unsupported layered layout prototype.
## Existing requirements and precedent
`PROJECT_GOAL.md` provides no numeric routing-latency requirement in the scoped search. `harness/release-routing-verification.md:172–184` supplies an existing initial100ms settled-solve target, explicitly not a universal guarantee:100 nodes/150edges/eight pins per edge measured release119ms full solve and2.4ms maximum single-edge preview (debug863ms/16.4ms). The119ms miss remains a recorded limitation. `harness/allocation-arrange-planner-20260923.md` explicitly disclaims large-scene latency. No frame-rate or universal routing SLA is inferred from these records.
`docs/language.rst:1235–1256` requires semantic-port precedence, suspension of authored route data for promoted folded endpoints, restoration on expansion, exact stored route metadata and explicit route-edit lifecycle. These are hard constraints. Automatic unpinned non-port attachment sides may legitimately change with routing cost; classify their coordinate changes as geometry results, not invariant violations.
## Frozen cases and trace tasks
Before any result, freeze manifest, all complete Projects/diagram identities, input hashes, generation source and variant binaries. Include original and folded workshop SA Allocation; a named mixed8–12-node scene with shared/distinct physical semantic ports, authored anchors/pins, a cycle and an untouched other view; its fixed relation-ID permutation with explicit old/new semantic correspondence; and a sparse40-node/~55-edge scene. Preserve all frozen cases in every report, including failures and censored calls.
The corpus author should record these concrete trace tasks by actual source/target/edge names and IDs before outputs: (1) workshop cross-container exchange in original and folded projection, identifying promoted visible ends; (2) mixed shared-output fan-out, identify each of at least two named targets without switching routes; (3) two distinct ports on the same card, trace each to its correct receiver; (4) cycle return edge, trace its direction back to the intended source; (5) authored pinned edge, identify the exact endpoint and passage through each pin; (6) sparse first-to-last long-span exchange plus one neighboring distractor. Repeat mixed tasks under the frozen ID permutation, using its semantic mapping. Do not select whichever routes look best after observation.
For later native inspection, all target identifications must be correct without consulting the source model, route recoloring, temporary geometry edits or hiding the distractors. Normal selection/zoom/pan are allowed and recorded. Report actions, wrong turns, uncertainty and time; no invented universal human completion-time threshold. Inspect at the same declared readable zoom and one Fit view, acknowledging Fit may be unreadable for40 nodes. No pure geometry metric substitutes for this task gate.
## Hard gates and geometry evidence
- No mutation of Projects or stored routes; semantic endpoint/edge identity, authored port anchors/attachments/pins, folds, filters and other-view records exact. Physical semantic-port tips remain exact. Dormant attachments remain stored. Promoted authored routes correctly suspended rather than incorrectly enforced; compare visibility/projection eligibility explicitly.
- No new missing route, nonfinite coordinate, invalid model, unrelated-node/header penetration or routing warning. Existing warning types must remain visible per edge; they cannot be averaged away. Authored unavoidable collision cases require exact predeclared exceptions, not blanket incident-edge exemption.
- Report every raw overlap interval and unique proper/T/bend/endpoint contact with edge IDs and locations. Classify common physical terminals but retain raw counts. Labels/headers/port labels must not obscure required routes in native review. Automatic attachment changes and label shifts are explicit results.
- No weighted aggregate quality pass. A new isolated crossing replacing coincidence is a reviewable tradeoff, not automatically failure or success. Adoption requires a predeclared trace task improvement or restored correctness and no newly ambiguous task elsewhere. ID sensitivity must be disclosed; a favorable naming/order cannot be chosen post hoc.
## Timing decision rule (proposed, not user-owned requirement)
Use optimized Windows variants with identical toolchain/profile and interleaved declared order. Parse/project outside the measured call; route_diagram alone is timed. One warmup plus seven measured samples per case; record each duration, median and maximum, not a claimed p95 from seven values. Verify identical output across repetitions outside the timed region. Exclude parsing/serialization/hash/drop work explicitly from the timer, while admitting that allocator/cache/OS state still affects observations.
For this modest frozen corpus, adopt the existing100ms target as the proposed per-case median ceiling and200ms maximum-sample ceiling. Also require candidate median <=1.25*released-baseline median +1ms per case; compare L against J as the simpler candidate too. These are deliberately declared engineering guardrails, subject to explicit future revision rather than post-result relaxation. If baseline itself fails the absolute ceiling, report a capacity limitation and do not treat relative improvement alone as a responsiveness pass. A meaningful correctness fix exceeding a guardrail needs a documented tradeoff and native response evidence; it is not an automatic pass.
Any completed warmup/measured call above5s censors the case and stops its remaining repetitions. Retain its actual elapsed time and failure status. This after-call cutoff cannot stop a hung individual call; parent supervision must provide a finite process timeout. Missing/censored samples never count as fast results. Seven interleaved samples are screening evidence, not a scaling or tail-latency theorem.
## Decision and stopping rule
Complete this fixed comparison once, investigate concrete correctness or measurement defects, and stop parameter tuning. Prefer the simpler J if L has no independently observable task benefit or exceeds the timing guardrails. Keep L experimental or discard it rather than add permanent settings to preserve sunk work. If none meets the rubric, report the failing constraint and choose the smallest conceptually different next experiment; do not quietly extend the corpus until a winner emerges. Production Command::Layout/reset integration, Undo/Redo/Save, desktop input behavior and native acceptance remain subsequent gates.
Driver/corpus source review is pending their readiness; this rubric makes no claim that they already implement these checks.
## Ready driver source review
Reviewed `crates/oa-core/examples/routing_cost_probe.rs` SHA256 `90ad27099a9486e9a7d45460bc9b66930e35d8336e3007fc30f90b48d88407d4` before compilation. No blocking source defect found for this protocol. The timer encloses routing plus result black_box; projection, parsing, cloned input, result equality/digest/serialization/destruction are outside. Seven full RoutedViews compare to warmup, with endpoint comparisons additionally emitted. Both warmup and samples can censor; median is absent for incomplete cases and stability_observed is false when warmup prevented all measured calls. Schema requires description in each case in addition to name/project_file/diagram. Paths are canonicalized under the manifest directory and duplicate case names reject.
The driver's censored case can still finish with process exit0 by design. External acceptance must require every expected case, complete=true, censored=false, seven measured samples, all equality flags true and project_unchanged=true; do not equate exit0 with responsiveness. A finite external process timeout is still required. The digest is correctly labeled noncryptographic; external corpus/source/binary hashes remain necessary. No execution occurred during this review. Corpus source review remains pending readiness.
## Final corpus and probe source review before execution
Read final prepared sources, with no builds/generation/routing calls by reviewer:
- `routing_eval_corpus.rs`: SHA256 `55ad185b3a72f5c1aa082732058604600cb016556c41aa5a3a21122766171bf6`.
- `routing_cost_probe.rs`: SHA256 `6f67abae2f912ed27215f8823b6dbcd41ca880b198dc60d5a10e88c71b38b8c0`.
- `auto_layout_probe.rs`: SHA256 `48e540f2176252d8ea1e110dd17fce37bd19f75f61fa6902356925bfe01540bc`.
No blocking source finding for the frozen five-case comparison. This completes the pending source review stated above; compilation/generation remain parent-owned verification.
Corpus constructs the saved12-placement SA Allocation workshop and its single collapse-flag change,10-function/14-exchange mixed case, reversed-edge-ID paired case, and40-function/55-exchange sparse case. No Layout/projection/router call constructs input geometry. Generated port IDs are v5-derived from fixed exchange IDs in ports::plan_functional_exchange; generated element/placement IDs are reidentified. The permutation uses temporary IDs and asserts inverse recovery of the entire Project, including authored-route references. Six fixed semantic-port anchors, an authored feedback pin/label, shared source/target ports and a separate-view sentinel provide meaningful independent constraints. The generator validates all cases before writing a fresh directory and refuses overwrite. Trace IDs, aliases, names and semantic endpoints are frozen in manifest metadata.
Coverage limits, not hidden successes: workshop contains no authored routes, so its folded case does not exercise suspension/restoration of a nonempty authored pin list. Mixed has semantic-port anchors and a pin/label but no explicit non-port EdgeAttachment. Sparse subsystem groups are flat named chains, not hierarchical containers. The frozen trace list selects representative branches; native review must inspect companion branches too to establish fan-out discrimination, using the manifest/model identities rather than selecting routes after seeing outputs. These are finite first-corpus limits, not blockers requiring the experiment to become comprehensive acceptance.
The geometry mode validates nonempty unique cases, Project validity and diagram existence; then calls metrics/roundtrip directly, without Layout/reset/candidate transformation. Analytic metric selfchecks still run before mode dispatch. Emitting full projected_edges, actual endpoint owners, effective pins, pin fractions and custom_suspended supports the required later semantic/geometry distinction. The output is observation, not an automatic oracle: later audit must compare authored/effective pins and port positions, account for folded promotion, and interpret legal automatic attachment changes. Full before_project and manifest remain present for this audit.
The updated cost schema intentionally removes deny_unknown_fields, retaining additional corpus/case metadata in flattened maps and emitting those maps. This now accepts generator trace_tasks/source_counts/metadata without losing them. Required typed fields remain required. Clock and censor logic agree with the earlier review. Neither probe must claim that a zero exit status alone establishes all semantic constraints or timing acceptance. External exact corpus/binary hashes and timeout remain necessary.
The geometry loader's relative-component check is less strict than the timing loader's canonical containment check (a symlink could resolve outside); for these parent-generated frozen ordinary files this is not a blocker. Both must read the same hashed files. No request is made for unrelated loader architecture or extra fixture families before the finite run.
@@ -1,37 +0,0 @@
# Independent routing analysis/supervisor source review
Static review before result analysis; no compiler, router, GUI or evaluator execution. Reviewed analyzer SHA256 `115258fe13f76ad77daacf0937955b14c497a4618e86a84c42c7e4ce845c1f24` and supervisor SHA256 `903c1c21971e7c5d73875db7df578c442496a17f98e4dde7a437d5f116f54604`. Line references below refer to those bytes.
## Actionable findings
1. Analyzer lines237–238 can falsely pass the rubric's no-new-penetration gate: total counts alone allow a new edge/node penetration to replace an old one. Compare identities from edge_node_details and node_collision_details using edge/node or unordered node pairs; retain segment/location/length changes for review. Keep the total vector, but do not label a lower/equal count as proof of no new affected object. This is material to automated acceptance; fix before relying on the report, without rerunning routers.
2. Lines116–118 check that each pin lies somewhere on the route and that fractions are sorted/in-range, but never bind a fraction to its corresponding pin. Wrong fractions or traversal assignment can pass. Interpolate the recorded polyline at each cumulative-length fraction and require the corresponding pin within tolerance. Current corpus has only one main authored pin, so multiple-pin order coverage is explicitly limited; it still supplies a nonvacuous fraction-position check.
Small useful consistency check at lines119–123: verify emitted source/target tips equal routed_edges.points first/last before using them as the physical-port oracle. The current producer directly emits those endpoints, so this is defensive evidence consistency rather than a demonstrated router defect. Do not require automatic non-port endpoint equality across variants.
## Sound scope and limitations
The analyzer requires exact case sets, optimized timing metadata, seven valid uncensored samples, stable full-route repetitions, unchanged Projects, independently recomputed medians/maxima, absolute100/200ms guardrails and declared relative guardrails. It binds raw receipt stream hashes, binary size/hash to the build receipt and current corpus hashes. Failures stay in the output and cause nonzero analysis status; no native/production acceptance is claimed. Nonfinite JSON is rejected. Per-edge warning-set comparison is appropriately stronger than total warning count. The model permutation inversion is meaningful for this explicitly named fixture; route-order sensitivity remains an observation rather than an equality requirement.
Effective pins and promoted-owner suspension are checked against full frozen Projects and projected definitions. Explicit non-port attachments and folded nonempty authored pins are absent from the corpus, as already recorded; do not claim those contracts fully exercised. Semantic-port checking skips absent projected ports, which is appropriate only with projection/folding evidence retained; do not generalize it as proof of hidden semantic-port placement. Projected nodes/ports/edges compare exactly, whereas legal automatic attachment sides remain observations.
Supervisor runs the declared released/J/L/L/J/released timing sequence, then separate geometry runs. It refuses existing attempt directories, checks binary/corpus before launch and after completion, captures stdout/stderr raw hashes, and has90s process timeout/kill. This is a finite whole-process timeout, not a guaranteed5s interruption of an individual route call. It preserves timed-out/nonzero receipts rather than silently omitting them; analyzer rejects them. Censored exit0 is also rejected by complete/sample checks. Build/source identity ultimately depends on parent's build-admission record, correctly noted by analyzer. No major timing-scope defect found.
## Corpus alias correction and actual byte evidence
Inspected source fix `f0eae74912061455453acd7ec17e2ddbe498ee2c`: after stable secondary placement reidentification, set alias to feedback_review_{i}. This addresses the observed random alias suffix without changing topology or geometry. The earlier source review established deterministic ID construction, not byte-identical generation; the original two generation folders remain preserved as counterevidence to the stronger claim.
Read-only comparison now confirms all six files in `.local/routing-independent-corpus-v2-20260925`, its `-v2-repeat-` counterpart and the frozen checked-in corpus at `f674e36c8b75dfa95246eabb672e36c937aec31b` are byte-identical. This is observed repeat-generation equality after correction, not an untested source inference. Manifest SHA256 `a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717`.
No request for broader framework changes or additional fixtures before this finite run. Apply the two concrete analysis fixes, retain the corpus limits, then assess actual results separately.
## Findings closed by source re-review
Reviewed corrected analyzer SHA256 `91383f12dc1c895f1b1dcffe6d99acc3358f0a2795fd9aff35baab2625dbc79d`, still without executing it or reading routing outcomes. Both material findings are addressed:
- collision_changes now keys edge penetration by edge/node/header-only identity and node collisions by unordered node pair. Added identities fail explicitly; removed/changed details and before/after route/node geometry remain in the report. This closes the equal-count substitution false pass.
- point_at_fraction independently computes cumulative polyline length and interpolates each reported pin fraction, then checks corresponding authored pin distance within0.001 world units. Empty, nonfinite and degenerate polylines receive explicit handling. This closes the unbound fraction-position check. Multiple-pin traversal coverage remains limited by the one-pin corpus, not falsely asserted.
The small optional endpoint-record consistency suggestion is not promoted to a blocking defect: producer fields are directly derived from the same point list. No outstanding material source-review finding prevents analysis of this finite corpus.
Also reviewed commit `095ab3b35847654d40e7bab9815c2bceb77484d1`: it extracts the same constraints, endpoint and routed-edge JSON mapping expressions into local Vec values before the outer json! macro. Field names, sources and iteration order remain unchanged; no router/corpus behavior change found. The preceding optimized build recursion-depth failure remains a failed build, not successful validation. Parent's rebuild outcome is outside this source review.
@@ -1,41 +0,0 @@
# Independent routing corpus contact review
Reviewed the completed three-variant geometry outputs and independent axis-interval audit, without builds, router reruns, GUI input or visual/native acceptance. All five cases are present for each of `released`, `j` and `lanes`. The audit's three recorded input SHA256 values match the actual geometry files reread for this review.
Evidence: `.local/routing-independent-contacts-20260925.json`, SHA256 `40b62731db7dc332b13021fa1f13bed176455feb2fb13d15998c761a4623b492`; standalone script `.local/audit-routing-corpus-contacts-20260925.py`, SHA256 `a6d95610a45faa3b4417df3c82059967d9729975fcf39dd1e9359ff1a20e0036`. The recorded primitive witnesses passed. The script uses independent axis-aligned interval intersection, rather than the Rust determinant intersection implementation.
## Agreement and measured tradeoffs
All **60 comparisons agree exactly**: raw unique point contacts, strict proper crossings, common-physical-terminal point contacts, and raw pairwise positive shared length, across 15 case/variant combinations. No nonzero numeric difference was found. These agreements validate these finite observations, not all possible geometry or a quality threshold.
Each table entry is **shared length / proper crossings / raw point contacts**. Shared lengths are diagram units; point contacts include proper crossings and T/vertex/end contacts.
| Case | Released | J | Lanes |
| --- | ---: | ---: | ---: |
| Workshop original | 1042 / 6 / 22 | 1074 / 5 / 23 | 602 / 5 / 23 |
| Workshop folded | 1096 / 7 / 20 | 1096 / 7 / 20 | 1096 / 7 / 20 |
| Mixed dispatch | 132 / 0 / 5 | 132 / 0 / 5 | 132 / 0 / 5 |
| Mixed, reversed edge IDs | 132 / 0 / 4 | 233.5999755859375 / 0 / 5 | 233.5999755859375 / 0 / 5 |
| Sparse 40 nodes | 496 / 24 / 32 | 372 / 25 / 31 | 372 / 25 / 31 |
The original workshop's lanes result reduces overlap substantially, while its nonproper contacts rise from 16 to 18: released has 8 T + 8 vertex contacts; lanes has 13 T + 5 vertex contacts. J has 11 T + 7 vertex contacts and a small overlap increase. The folded case's listed metrics are unchanged; this does not assert point-for-point route equality.
Both candidates worsen overlap in the edge-ID-permuted mixed case, adding one T contact (released 1 T + 3 vertex contacts; candidates 2 T + 3). The nonpermuted mixed case stays at 2 T + 3 vertex contacts. Consequently these observations do not establish ID-order invariance. Sparse routing trades 124 fewer shared units and one fewer raw contact for one additional proper crossing. Neither candidate uniformly dominates released routing on this corpus. These facts should remain visible in an adoption decision rather than being collapsed into a favorable single score.
## Ports, folded endpoints, and authored pin interpretation
All three variants' emitted tips for the two mixed cases match their referenced semantic ports' emitted positions **and projected owner IDs**: 28 ends per case, no missing ports or mismatch. The sparse case similarly matches all 110 ends per variant. This is a consistency check between independently selected records in the geometry output; it does not certify fixed-anchor fraction computation against source or prove all semantic conservation.
The common-terminal point count is zero in all 15 observations, despite deliberately reused semantic ports. This is not evidence that routes never share tips: a positive collinear shared interval is not enumerated as infinitely many point contacts. The interval audit explicitly retains common-terminal classifications. For example, mixed dispatch contains four segment-pair overlap intervals on edge pairs with a common terminal, three of which contain the common terminal itself. The permuted candidates contain five such intervals, still three containing the terminal. No common-tip overlap is subtracted from the raw length.
The original workshop projects 12 nodes/12 edges; folded projects 9 nodes/11 edges in all variants. Resolving relation endpoints through actual port owners and stored placements identifies four folded endpoint promotions in each output: target of `sa_relay_to_rescue`, source of `sa_direct_advice`, target of `validated_distress_report`, and source of `sa_advice_to_relay`. Original workshop has no such owner promotion. These are legitimate folded presentation changes, not semantic reconnections. Both workshop source cases have zero authored route records, so they cannot establish preservation or passage of suspended authored pins.
In each mixed case and each variant, the one authored feedback waypoint `(300,-100)` lies on the emitted route at arc distance 1392, and ordered passage is observed. The original sentinel edge is `00000000-0000-0000-0000-00000001adbd`; the reversed-ID counterpart is `00000000-0000-0000-0000-00000001adb0`. This verifies six concrete waypoint passages, not general retention of every route field. The other-view sentinel is not rendered by these selected-view observations and is left to the separate metadata analyst. Emitted geometry lacks `custom_suspended`; the audit deliberately reports absence/passage without calling every absent pin a failure.
## Mathematical and evidence limits
Contacts deduplicate per edge pair and coordinate within EPS=0.0001; a physical location shared by three edges may count three pairwise contacts. Proper means interior to both tested segments; a visually crossing route at a bend or redundant vertex can instead appear under T/vertex classification. Labels describe primitive geometry, not perceived topology or usability. Positive collinear intervals are summed per segment pair with multiplicity, not union length; shared-run endpoints can also appear as point contacts when another segment pair supplies a point witness. Common-terminal classification requires equal projected owner plus coincident physical endpoint, and never exempts a raw count.
The script rejects nonorthogonal segments and uses axis tolerance, unlike Rust's determinant/quantization details. Tiny near-tolerance geometry may produce different results even though every metric agrees here. Stroke width, arrowheads, port labels, glyphs, perceptual traceability, runtime and native interaction are outside this audit. Automatic non-port attachment choices may legitimately differ between routers and are not treated as preservation failures.
The parent is separately diagnosing emitted f32 serialization/model-comparison differences. This review does not resolve that issue or infer changed accepted input Projects from decimal spellings. Expected corpus inputs remain the frozen inputs; complete stored metadata/source/Project preservation belongs to the separate audit. There is no visual or native acceptance claim.
@@ -1,21 +0,0 @@
# Frozen source-first routing corpus (#32)
Prepared from f72aa2ca without calling Layout, projection, routing, or reading new routing results. This defines inputs and invariants, not expected quality. Generator ownership: `crates/oa-core/examples/routing_eval_corpus.rs`; no production changes. Generation, validation, serialization, and disk I/O are outside routing timing.
## Cases fixed before generation
1. `workshop_sa_original`: decode the embedded existing `examples/routing-workshop.json` through the production persistence decoder. Select Allocation view `sa_system_boundary_and_functions`, UUID `cb21862d-79e1-5a9d-bdf0-ee344c2fb219`, with 12 authored placements. Preserve the complete loaded Project. The saved source currently has six views and no authored routes: preserving these empty route records is explicit, not claimed pin coverage.
2. `workshop_sa_folded`: clone case 1 and set only the placement of `rescue_coordination_system` to collapsed. Semantic records, other views, all placement positions/sizes, routes and labels stay exact. This exercises hidden descendants and promoted endpoints through an actual allocation view. No generated route result is used to select the fold.
3. `mixed_dispatch`: ten named Functions (Sensor A, Sensor B, Ingest, Validate, Archive, Correlate, Plan, Dispatch, Actuator, Operator) and 14 FunctionalExchanges. Edges in authored order: A→Ingest; B→Ingest; Ingest→Validate; Ingest→Archive; Validate→Correlate; Archive→Correlate; Correlate→Plan; Plan→Dispatch; Dispatch→Actuator; Dispatch→Operator; Operator→Actuator; Archive→Actuator; B→Archive; Plan→A. The final edge is explicit feedback; branching can create more than one graph-theoretic cycle. A/B→Ingest reuse one semantic input; Ingest fan-out and Dispatch fan-out each reuse one output. Other endpoints are explicitly distinct. Empty carried-item contracts are legal and avoid unrelated data typing. Six fixed anchor records include opposite-side feedback and vertical fan-out. Plan→A carries one authored waypoint and a label offset sentinel. A separate three-placement FunctionalDataflow view carries its own route/label sentinel. No Layout is used to construct either view.
4. `mixed_dispatch_edge_ids_reversed`: exact clone of case 3 with the 14 relation IDs reversed across their original sorted set, using a collision-free temporary ID domain and production `reidentify` for every reference. Names, endpoint semantics, port identities, aliases, positions, and authored route geometry retain correspondence. The inverse permutation must recover the exact original Project. This diagnoses relation-ID order sensitivity; exact geometric equality is an observation, not assumed quality success.
5. `subsystems_40_sparse`: five named subsystems, each with eight named processing stages, represented as 40 flat Function placements. Seven consecutive stage links in each subsystem (35), plus four cross-subsystem links per subsystem to its successor modulo five (20), totaling 55 distinct FunctionalExchanges. Cross links go stages 1/3/5/7 to successor stages 0/2/4/6. Positions are a predeclared 8-column × 5-row stage/subsystem grid. Every endpoint explicitly uses a distinct semantic port. This modest sparse cyclic workload is not the earlier diamond/bipartite corpus.
## Trace tasks and invariants
Predeclared trace tasks: workshop aliases `sa_report_to_relay`, `sa_direct_advice`, `sa_incident_decision`; mixed Sensor B→Ingest (shared target input), Ingest→Archive (shared source output), Dispatch→Operator, and feedback Plan→Sensor A; sparse subsystem 0 stage 1→subsystem 1 stage 0 and subsystem 4 stage 7→subsystem 0 stage 6. The manifest records trace edge identities and endpoints from the source model.
Every generated Project must pass `validate_candidate` before any output directory is created. JSON files serialize complete Projects directly. Manifest schema is 1; each case has name, relative project_file, diagram UUID, description, source counts, trace tasks, and relevant correspondence/sentinel metadata. Stable IDs and unique aliases are assigned independently of routing. Repeated generation should give byte-identical output; this is for the parent to verify, not asserted as already run.
Routing must preserve complete input Project bytes/model identity, semantic port assignments, authored routes/labels/attachments, fixed anchors, fold flags, and other views. Automatic non-port attachment-side choices are routing results, not preservation failures. The workshop contains no authored route sentinels; mixed cases supply that coverage. A promoted route may suspend authored geometry in rendered output while its stored metadata must remain intact. The generator does not prescribe which route topology, automatic side, contact count, length, or warning count is acceptable.
Usage (parent execution only): `cargo run --locked --offline -p oa-core --example routing_eval_corpus -- NEW_DIRECTORY`. The destination must not exist; manifest is written last. Existing files are never overwritten. No corpus generation, compiler, formatter, or router execution by this author before handoff.
@@ -1,271 +0,0 @@
{
"cases": [
{
"description": "Saved coastal rescue Allocation view, all source records retained.",
"diagram": "cb21862d-79e1-5a9d-bdf0-ee344c2fb219",
"metadata": {
"source": "examples/routing-workshop.json",
"view_alias": "sa_system_boundary_and_functions"
},
"name": "workshop_sa_original",
"project_file": "workshop_sa_original.json",
"source_counts": {
"elements": 75,
"relations": 62,
"selected_view_authored_routes": 0,
"selected_view_placements": 12,
"views": 6
},
"trace_tasks": [
{
"alias": "sa_report_to_relay",
"edge": "4678335a-04ae-5a19-a302-ea583bdd6c65",
"name": "Report to relay",
"source": "f5497540-43a7-5573-826b-61eb7e4760a9",
"target": "8b23ecf0-f5ce-57cf-8bce-8e0c08f89436"
},
{
"alias": "sa_direct_advice",
"edge": "956d5b0a-1e34-518f-b46d-425751998bbc",
"name": "Direct advice",
"source": "b8896811-d893-50fc-b695-d2ee07dae9e3",
"target": "febf00a2-efed-5faf-b8c2-5d4bc77ddb53"
},
{
"alias": "sa_incident_decision",
"edge": "526753bc-88b0-5322-bffc-1b36376becf1",
"name": "Incident decision",
"source": "b05744bd-4dce-54b7-a9ff-8861d11dc1e0",
"target": "b8896811-d893-50fc-b695-d2ee07dae9e3"
}
]
},
{
"description": "Same saved Project with only rescue_coordination_system placement folded.",
"diagram": "cb21862d-79e1-5a9d-bdf0-ee344c2fb219",
"metadata": {
"folded_element": "30fc41ea-fc3d-5b57-9a05-67b14425fad9",
"folded_placement": "75920e7a-4586-58b7-9eb2-7e0a3d8a1825",
"source": "examples/routing-workshop.json",
"unfold_restores_original_exact": true
},
"name": "workshop_sa_folded",
"project_file": "workshop_sa_folded.json",
"source_counts": {
"elements": 75,
"relations": 62,
"selected_view_authored_routes": 0,
"selected_view_placements": 12,
"views": 6
},
"trace_tasks": [
{
"alias": "sa_report_to_relay",
"edge": "4678335a-04ae-5a19-a302-ea583bdd6c65",
"name": "Report to relay",
"source": "f5497540-43a7-5573-826b-61eb7e4760a9",
"target": "8b23ecf0-f5ce-57cf-8bce-8e0c08f89436"
},
{
"alias": "sa_direct_advice",
"edge": "956d5b0a-1e34-518f-b46d-425751998bbc",
"name": "Direct advice",
"source": "b8896811-d893-50fc-b695-d2ee07dae9e3",
"target": "febf00a2-efed-5faf-b8c2-5d4bc77ddb53"
},
{
"alias": "sa_incident_decision",
"edge": "526753bc-88b0-5322-bffc-1b36376becf1",
"name": "Incident decision",
"source": "b05744bd-4dce-54b7-a9ff-8861d11dc1e0",
"target": "b8896811-d893-50fc-b695-d2ee07dae9e3"
}
]
},
{
"description": "Ten-function sensing/decision/dispatch network, explicit port sharing and fixed anchors.",
"diagram": "00000000-0000-0000-0000-0000000186a1",
"metadata": {
"authored_label_count_main": 1,
"authored_waypoint_count_main": 1,
"declared_feedback_cycle": [
"00000000-0000-0000-0000-000000018704",
"00000000-0000-0000-0000-000000018708",
"00000000-0000-0000-0000-00000001870a",
"00000000-0000-0000-0000-00000001870e",
"00000000-0000-0000-0000-000000018710",
"00000000-0000-0000-0000-000000018704"
],
"fixed_anchor_records": 6,
"secondary_diagram": "00000000-0000-0000-0000-0000000186a2",
"sentinel_edge": "00000000-0000-0000-0000-00000001adbd",
"shared_input": "ebfcf690-4ac5-5976-864c-337d844b6cd6",
"shared_outputs": [
"9244d718-d53a-54cb-a920-5b5312576da6",
"169224b3-b692-540d-ac73-1435e2a87b04"
]
},
"name": "mixed_dispatch",
"project_file": "mixed_dispatch.json",
"source_counts": {
"elements": 35,
"relations": 14,
"selected_view_authored_routes": 1,
"selected_view_placements": 10,
"views": 2
},
"trace_tasks": [
{
"alias": "flow_01",
"edge": "00000000-0000-0000-0000-00000001adb1",
"name": "Sensor B observations",
"source": "00000000-0000-0000-0000-000000018706",
"target": "00000000-0000-0000-0000-000000018708"
},
{
"alias": "flow_03",
"edge": "00000000-0000-0000-0000-00000001adb3",
"name": "Archive incoming observations",
"source": "00000000-0000-0000-0000-000000018708",
"target": "00000000-0000-0000-0000-00000001870c"
},
{
"alias": "flow_09",
"edge": "00000000-0000-0000-0000-00000001adb9",
"name": "Operator dispatch copy",
"source": "00000000-0000-0000-0000-000000018712",
"target": "00000000-0000-0000-0000-000000018716"
},
{
"alias": "flow_13",
"edge": "00000000-0000-0000-0000-00000001adbd",
"name": "Sensor A sampling feedback",
"source": "00000000-0000-0000-0000-000000018710",
"target": "00000000-0000-0000-0000-000000018704"
}
]
},
{
"description": "Same mixed Project with fixed reversed relation-ID permutation, remapped references.",
"diagram": "00000000-0000-0000-0000-0000000186a1",
"metadata": {
"edge_id_correspondence": {
"00000000-0000-0000-0000-00000001adb0": "00000000-0000-0000-0000-00000001adbd",
"00000000-0000-0000-0000-00000001adb1": "00000000-0000-0000-0000-00000001adbc",
"00000000-0000-0000-0000-00000001adb2": "00000000-0000-0000-0000-00000001adbb",
"00000000-0000-0000-0000-00000001adb3": "00000000-0000-0000-0000-00000001adba",
"00000000-0000-0000-0000-00000001adb4": "00000000-0000-0000-0000-00000001adb9",
"00000000-0000-0000-0000-00000001adb5": "00000000-0000-0000-0000-00000001adb8",
"00000000-0000-0000-0000-00000001adb6": "00000000-0000-0000-0000-00000001adb7",
"00000000-0000-0000-0000-00000001adb7": "00000000-0000-0000-0000-00000001adb6",
"00000000-0000-0000-0000-00000001adb8": "00000000-0000-0000-0000-00000001adb5",
"00000000-0000-0000-0000-00000001adb9": "00000000-0000-0000-0000-00000001adb4",
"00000000-0000-0000-0000-00000001adba": "00000000-0000-0000-0000-00000001adb3",
"00000000-0000-0000-0000-00000001adbb": "00000000-0000-0000-0000-00000001adb2",
"00000000-0000-0000-0000-00000001adbc": "00000000-0000-0000-0000-00000001adb1",
"00000000-0000-0000-0000-00000001adbd": "00000000-0000-0000-0000-00000001adb0"
},
"inverse_recovers_original_exact": true,
"paired_case": "mixed_dispatch",
"secondary_diagram": "00000000-0000-0000-0000-0000000186a2"
},
"name": "mixed_dispatch_edge_ids_reversed",
"project_file": "mixed_dispatch_edge_ids_reversed.json",
"source_counts": {
"elements": 35,
"relations": 14,
"selected_view_authored_routes": 1,
"selected_view_placements": 10,
"views": 2
},
"trace_tasks": [
{
"alias": "flow_01",
"edge": "00000000-0000-0000-0000-00000001adbc",
"name": "Sensor B observations",
"source": "00000000-0000-0000-0000-000000018706",
"target": "00000000-0000-0000-0000-000000018708"
},
{
"alias": "flow_03",
"edge": "00000000-0000-0000-0000-00000001adba",
"name": "Archive incoming observations",
"source": "00000000-0000-0000-0000-000000018708",
"target": "00000000-0000-0000-0000-00000001870c"
},
{
"alias": "flow_09",
"edge": "00000000-0000-0000-0000-00000001adb4",
"name": "Operator dispatch copy",
"source": "00000000-0000-0000-0000-000000018712",
"target": "00000000-0000-0000-0000-000000018716"
},
{
"alias": "flow_13",
"edge": "00000000-0000-0000-0000-00000001adb0",
"name": "Sensor A sampling feedback",
"source": "00000000-0000-0000-0000-000000018710",
"target": "00000000-0000-0000-0000-000000018704"
}
]
},
{
"description": "Five eight-stage subsystem chains with twenty directed cross-subsystem handoffs; all ports distinct.",
"diagram": "00000000-0000-0000-0000-000000030d41",
"metadata": {
"all_exchange_ports_distinct": true,
"chain_edges": 35,
"cross_edges": 20,
"grid_columns": 8,
"grid_rows": 5,
"groups": [
"Sensing",
"Communications",
"Assessment",
"Planning",
"Delivery"
],
"stages": [
"Acquire",
"Decode",
"Validate",
"Enrich",
"Aggregate",
"Decide",
"Package",
"Publish"
]
},
"name": "subsystems_40_sparse",
"project_file": "subsystems_40_sparse.json",
"source_counts": {
"elements": 150,
"relations": 55,
"selected_view_authored_routes": 0,
"selected_view_placements": 40,
"views": 1
},
"trace_tasks": [
{
"alias": "flow_35",
"edge": "00000000-0000-0000-0000-000000033473",
"name": "Sensing Decode handoff to Communications Acquire",
"source": "00000000-0000-0000-0000-000000030da6",
"target": "00000000-0000-0000-0000-000000030db4"
},
{
"alias": "flow_54",
"edge": "00000000-0000-0000-0000-000000033486",
"name": "Delivery Publish handoff to Sensing Package",
"source": "00000000-0000-0000-0000-000000030df2",
"target": "00000000-0000-0000-0000-000000030db0"
}
]
}
],
"construction": "Source-authored positions/topology, no Layout/projection/routing calls; validate all before writing.",
"definition_baseline": "f72aa2ca",
"generation_in_routing_timing": false,
"invariants": "Routing is read-only. Preserve all semantic records, port identities, fixed anchors, authored routes/labels, fold flags, and other views. ID permutation correspondence is explicit. No quality or automatic endpoint-side expectation.",
"schema": 1
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,55 +0,0 @@
# Independent routing decision review
**Recommendation: retain the released router in the Arrange-reset candidate. Keep J and L as published experiments; do not tune further on either corpus.** The new evidence supports a meaningful L overlap improvement in one realistic view, but does not satisfy the predeclared native trace-task adoption gate and includes label/ID-order regressions. This is a bounded decision, not a finding that the released router is already satisfactory.
## Exact runs and integrity
Optimized variants: released-equivalent router at `4fb3cdc721e6fb8d70141b9c8f59809c53e7f16c`; J at `3ea0e23b70edfcaf61b1e900afb00254c7e80f75`; L at `095ab3b35847654d40e7bab9815c2bceb77484d1`. These are evaluator-bearing source pins, not three releases. Frozen corpus commit `f674e36c8b75dfa95246eabb672e36c937aec31b` and manifest hash `a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717`.
Independently checked all nine timing/geometry receipts: process exit0, no timeout, corpus/binary unchanged, raw stdout/stderr lengths and SHA256 match receipts. Recomputed timing summaries for six runs ×five cases ×seven samples=210 measured calls, all complete/uncensored with full-route repeat equality and unchanged Project flags. No rerun, compilation or native action performed during this audit.
## Practical timing result
The predefined100ms median/200ms maximum and relative1.25×baseline+1ms screening checks pass. Observed median ranges across the two interleaved passes:
| Variant | Workshop original | Mixed original | Mixed reversed IDs | Sparse40 |
|---|---:|---:|---:|---:|
| Released |0.541–0.663ms|0.213–0.215ms|0.179–0.202ms|2.260–2.704ms|
| J |0.441–0.716ms|0.259–0.285ms|0.331–0.477ms|2.225–2.306ms|
| L |0.577–0.579ms|0.407–0.422ms|0.365–0.589ms|2.966–3.210ms|
Maximum observed measured call6.196ms; every case median below3.3ms. The+1ms relative allowance intentionally matters when baseline calls are submillisecond; passing it does not mean zero overhead. L is slower on sparse/mixed cases but comfortably passes these modest-corpus absolute screens. The earlier debug routing_geometry suite4.30→16.43s remains a separate cost signal; it cannot override or be substituted for these optimized route-only observations. Neither dataset proves a general latency bound, scaling law, p95, worst-case timeout or native input responsiveness.
## Quality tradeoffs against released routing
| Case | J | L |
|---|---|---|
| Workshop original |sharing1042→1074; proper6→5; contacts22→23; label/node11→13; label/stroke5→6|sharing1042→602; proper6→5; contacts22→23; label/node11→12; label/stroke5→6; length+24; area+12756|
| Workshop folded |reported scalar vector unchanged|unchanged|
| Mixed original |unchanged|unchanged|
| Mixed reversed IDs |sharing132→233.5999756; contacts4→5|same regression|
| Sparse40 |sharing496→372; proper24→25; contacts32→31; label/stroke15→13; area+8960|same changes|
L removes440 raw shared units in workshop (970→530 nonterminal), a substantial improvement worth retaining as evidence. It still adds a label/node collision and unrelated label/stroke intersection. J's smaller scoring patch is theoretically motivated and improved the earlier diamond, yet this realistic workshop and fixed-ID permutation expose regressions. Fewer proper crossings or contacts cannot automatically excuse shared trunks, obscured labels or wrong-turn ambiguity. The unchanged folded case and mixed original do not make ID sensitivity disappear.
Earlier37-scene evidence remains consistent with a non-dominating tradeoff: J solved diamond's extra trunk but regressed original bipartite overlap; P offered no layered benefit; L/PL improved layered bipartite only11 shared units and left104 nonterminal units. P+L traded baseline overlap for an isolated crossing. These are finite observations rather than an adoption score. Do not select favorable graph IDs or add another penalty coefficient after seeing results.
## Analysis-v1 failure remains explicit
The current analysis has six `frozen_project_exact` failures, one per mixed case/variant. Independent inspection of mixed original shows only typed fractional values expanded by serde_json::Value: anchor offsets0.3/0.6 and label fractions0.4 become their exact f32-to-f64 expansions. This supports the representation-mismatch diagnosis, not a blanket tolerance waiver. Parent's separate typed-normalization-v2 check must close every discrepancy at schema-known f32 fields while keeping identities, strings, arrays and other numeric fields exact. Preserve analysis-v1 and its failed status. This review does not silently relabel those six failures as passed.
All other existing analysis checks pass, including projected identity/geometry, effective pins/fractions, physical visible semantic-port tips, warning sets, and no-new node/penetration identities. That is scoped evaluator evidence, not independent verification of every hidden-port or explicit-attachment case. The independent contact audit is available and bound below; native task assessment remains absent.
## Adoption boundary
The frozen rubric requires correct source-to-target trace tasks and no newly ambiguous task elsewhere. No native trace-task result exists; approximate core label rectangles cannot prove actual text readability. Therefore neither J nor L earns production adoption merely by passing timing. Keep the reset candidate independent on released routing and verify its explicit reset/history/source contract. If future native evaluation is undertaken, use the already frozen named tasks and report uncertainty/wrong turns without changing fixture geometry. Do not broaden this into indefinite tuning or silently change the adoption rubric.
Evidence SHA256: analysis-v1 `1634f06ef7c4e50ebcbec64423a9a8730c08c822bf0023572e62ca0281c96302`; independent contact audit `40b62731db7dc332b13021fa1f13bed176455feb2fb13d15998c761a4623b492`. No production acceptance, #32 closure or native observation claimed.
## Typed-serialization finding closed
Reviewed v2 analyzer SHA256 `a72895248175fc56667d7b86cb4120a840d931e74ab1149e9649bb82d179f1ae`. Its comparison policy applies exact IEEE754 binary32 bit equality ONLY at schema-declared Diagram node PortAnchor.offset and route EdgeLabel.fraction paths. It requires finite numeric values in[0,1], preserves dict keys/list lengths, and compares every other field and type exactly. It does not apply a global numeric tolerance or alter raw evidence.
Independently inspected all15 reported Project comparisons:30 differing leaves across exactly six mixed-case/variant observations, five typed fractional paths each. Every pair independently packs to identical binary32 bytes. No other differences are reported. V2 has zero failed checks. Verified script/output and original-before/original-after hashes directly against current bytes; original failed report remains `1634f06e...` unchanged. V2 report SHA256 `88af679275d85dad44a10dfb1eb4da94b861125c5948062c450635bdeb9814fd`.
This closes the six representation-related Project equality failures without rerouting, changing the corpus or weakening other-field equality. Earlier section records the truthful v1 state and is superseded only on that finding. The production recommendation is unchanged: retain released routing for the reset candidate; J/L remain experiments pending the unmet native trace-task criterion. No timing or geometry quality numbers were changed by this normalization review.

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