Compare commits

..
Author SHA1 Message Date
Codex-ytr83r 3e21c1bca2 Bound complete member displacement across large origins 2026-09-24 21:52:38 -07:00
Codex-ytr83r 42f595a5d6 Probe dependency-aware ordering across container boundaries 2026-09-24 21:50:15 -07:00
Codex-ytr83r c02a03c553 Declare dependency-aware boundary ordering comparison 2026-09-24 21:48:07 -07:00
Codex-ytr83r f4fa0c11f2 Record SCC placement evidence and bounded transfer correction 2026-09-24 21:37:03 -07:00
Codex-ytr83r 2426d28648 Preserve requested container minima after placement transfer 2026-09-24 21:24:57 -07:00
Codex-ytr83r 4dd764fa6c Use mutable reachability rows in isolated SCC probe 2026-09-24 21:17:11 -07:00
Codex-ytr83r ea18adc061 fix(experiment): score occupied perimeter cells including one-column cycles 2026-09-24 21:11:19 -07:00
Codex-ytr83r 5300a8c803 experiment(layout): keep cyclic quotient groups compact in condensation order 2026-09-24 21:09:04 -07:00
Codex-ytr83r ae9dad54b7 Record bounded placement clearance result and preserved quality regressions 2026-09-24 20:57:17 -07:00
Codex-ytr83r 074051261a test(layout): use valid record types for non-port lead fixtures 2026-09-24 20:40:41 -07:00
Codex-ytr83r 2be8c7f292 experiment(layout): diagnose mandatory leads and test bounded flat separation 2026-09-24 20:38:33 -07:00
Codex-ytr83r 2850b915d6 Record placement reference failures and port-clearance requirements 2026-09-24 20:26:23 -07:00
Codex-ytr83r fc5c22c903 Preserve authored sizes during identity placement transfer 2026-09-24 20:18:39 -07:00
Codex-ytr83r 8a2010d8a6 Add bounded external placement comparison and preservation adapter 2026-09-24 20:12:01 -07:00
Codex-ytr83r ac5d7ef34a Describe recorded evidence without implying blocked publication 2026-09-24 19:16:59 -07:00
Codex-ytr83r ae86111f22 Record independent routing corpus decision and preserved evidence 2026-09-24 19:12:27 -07:00
Codex-ytr83r 4fb3cdc721 Observe released router 715036e1 in frozen common harness 2026-09-24 18:53:15 -07:00
Codex-ytr83r 3ea0e23b70 Observe j router 08656b18 in frozen common harness 2026-09-24 18:46:28 -07:00
Codex-ytr83r 095ab3b358 Split geometry serialization to stay within macro recursion depth 2026-09-24 18:44:56 -07:00
Codex-ytr83r f674e36c8b Freeze byte-identical independent routing inputs and review 2026-09-24 18:37:26 -07:00
Codex-ytr83r f0eae74912 Make secondary corpus placement aliases deterministic 2026-09-24 18:36:18 -07:00
Codex-ytr83r a879341cfc Define frozen routing corpus and isolated timing protocol 2026-09-24 18:33:37 -07:00
Codex-ytr83r f72aa2ca5c Record lane tradeoffs, verification and runtime concern 2026-09-24 18:20:21 -07:00
Codex-ytr83r e8ec6dbb31 Isolate parallel lanes with the original overlap coefficient 2026-09-24 18:13:07 -07:00
Codex-ytr83r d0be9ff067 Probe bounded parallel lanes after capped penalty comparison 2026-09-24 18:09:48 -07:00
Codex-ytr83r 3d7adff923 Experiment with fixed capped overlap penalty at unchanged geometry 2026-09-24 18:03:48 -07:00
Codex-ytr83r 9c02100d23 Preserve terminal scoring experiment with ordinary-scene regressions 2026-09-24 18:02:45 -07:00
Codex-ytr83r 08656b18bf Resolve diagnostic probe strict Clippy findings 2026-09-24 17:59:36 -07:00
Codex-ytr83r 497c1ad8b3 Account for target joins when selecting route legs 2026-09-24 17:53:47 -07:00
Codex-ytr83r 427078461a Record first automatic layout experiment and shared-route regressions 2026-09-24 17:49:29 -07:00
Codex-ytr83r e7deea7039 experiment: compare automatic layout against independent geometry metrics 2026-09-24 17:40:49 -07:00
117 changed files with 28699 additions and 1062 deletions
-1
View File
@@ -12,7 +12,6 @@
*.png binary
*.jpg binary
*.zip binary
harness/prerelease37-independent-9e8r6t-20260924/** -text whitespace=cr-at-eol
# Exact source/recovery oracles and archived ledgers retain their measured bytes.
# Keep ordinary text diffs; only disable checkout/check-in newline conversion.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,131 @@
//! 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
}
@@ -0,0 +1,279 @@
//! 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());
}
}
@@ -0,0 +1,654 @@
//! 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 }]
);
}
}
@@ -0,0 +1,686 @@
//! 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);
}
}
@@ -0,0 +1,380 @@
//! Isolated #32 experiment, not a production layout engine.
//! Uses existing Layout sizing, three deterministic ordering passes, and one
//! core-estimated-label spacing pass. Automatic elbows remain derived. Folded/omitted
//! node topology is explicitly unsupported; filtered edges retain their metadata.
use oa_core::{Command, Id, ModelError, Position, Project, Size, projection, routing};
use std::collections::{BTreeMap, BTreeSet};
const WORK_LIMIT: usize = 200_000;
const NODE_LIMIT: usize = 256;
const EDGE_LIMIT: usize = 1024;
fn spend(work: &mut usize) -> Result<(), ModelError> {
*work += 1;
if *work > WORK_LIMIT {
return Err(ModelError("Layered probe work limit exceeded.".into()));
}
Ok(())
}
/// Return a new Project; caller owns comparison, history and serialization.
pub fn candidate(project: &Project, diagram: Id) -> Result<Project, ModelError> {
let original = project
.diagrams
.get(&diagram)
.ok_or_else(|| ModelError("Missing probe diagram.".into()))?;
let view = projection::project_diagram(project, original);
if view.nodes.len() > NODE_LIMIT || view.edges.len() > EDGE_LIMIT {
return Err(ModelError("Layered probe graph limit exceeded.".into()));
}
if view.nodes.len() != original.nodes.len() || view.nodes.iter().any(|n| n.collapsed) {
return Err(ModelError(
"Layered probe does not support folded/omitted node topology.".into(),
));
}
let routed = routing::route_diagram(project, original, &view);
let eligible: BTreeSet<_> = view
.edges
.iter()
.filter(|edge| {
projection::edge_endpoint_placements(project, original, edge.id)
== Some((edge.source, edge.target))
&& routed
.edges
.get(&edge.id)
.is_some_and(|route| !route.custom_suspended)
})
.map(|edge| edge.id)
.collect();
let mut result = oa_core::prepare_command(project, &Command::Layout(diagram))?.project;
// Discard baseline route translation: final routes are reconstructed directly
// from original geometry, avoiding two translations and preserving list order.
result.diagrams.get_mut(&diagram).unwrap().routes = original.routes.clone();
for route in &mut result.diagrams.get_mut(&diagram).unwrap().routes {
if eligible.contains(&route.edge) {
route.waypoints.clear();
route.label = None;
}
}
let baseline = projection::project_view(&result, diagram);
let labels = routing::route_diagram(&result, &result.diagrams[&diagram], &baseline);
let mut gap_x = 64.0_f32;
let mut gap_y = 32.0_f32;
for edge in labels.edges.values() {
gap_x = gap_x.max(edge.label.bounds.size.width + 24.0);
gap_y = gap_y.max(edge.label.bounds.size.height + 24.0);
if let Some(relation) = result.relations.get(&edge.id) {
for end in routing::association_end_geometry(relation, edge) {
gap_x = gap_x.max(end.label.bounds.size.width + 24.0);
gap_y = gap_y.max(end.label.bounds.size.height + 24.0);
}
}
}
if !gap_x.is_finite() || !gap_y.is_finite() {
return Err(ModelError("Nonfinite estimated label bound.".into()));
}
let parents: BTreeMap<_, _> = baseline
.nodes
.iter()
.map(|n| (n.id, n.visual_parent))
.collect();
let mut children: BTreeMap<Option<Id>, Vec<Id>> = BTreeMap::new();
for node in &baseline.nodes {
children
.entry(node.visual_parent)
.or_default()
.push(node.id);
}
let names: BTreeMap<_, _> = baseline
.nodes
.iter()
.map(|n| (n.id, (result.elements[&n.element].alias.clone(), n.id)))
.collect();
for siblings in children.values_mut() {
siblings.sort_by_key(|id| names[id].clone());
}
let minima: BTreeMap<_, _> = baseline.nodes.iter().map(|n| (n.id, n.size)).collect();
let headers: BTreeMap<_, _> = baseline
.nodes
.iter()
.map(|n| {
(
n.id,
if original.projection.state_machine().is_some() {
projection::state_header_height(&result, n.element)
} else {
64.0
},
)
})
.collect();
let mut positions: BTreeMap<_, _> = baseline.nodes.iter().map(|n| (n.id, n.position)).collect();
let mut sizes = minima.clone();
let mut work = 0;
let mut group_order: Vec<_> = children.keys().copied().collect();
group_order.sort_by_key(|parent| {
parent.map_or(0, |id| {
baseline.nodes.iter().find(|n| n.id == id).unwrap().depth + 1
})
});
let mut groups = BTreeMap::new();
for pass in 0..3 {
for parent in &group_order {
let siblings = &children[parent];
let mut arcs = BTreeSet::new();
for edge in &baseline.edges {
spend(&mut work)?;
let a = child_under(edge.source, *parent, &parents, &mut work)?;
let b = child_under(edge.target, *parent, &parents, &mut work)?;
if edge.oriented
&& let (Some(a), Some(b)) = (a, b)
&& a != b
{
arcs.insert((a, b));
}
}
let ranks = ranks(siblings, &arcs, &mut work)?;
let mut layers: BTreeMap<usize, Vec<Id>> = BTreeMap::new();
for id in siblings {
layers.entry(ranks[id]).or_default().push(*id);
}
// Boundary neighbours participate even though they are not siblings.
// Incoming preference anchors the downstream order to its upstream
// counterpart instead of swapping both sides simultaneously.
let mut scores = BTreeMap::new();
for id in siblings {
let mut incoming = Vec::new();
for edge in &baseline.edges {
spend(&mut work)?;
let a = child_under(edge.source, *parent, &parents, &mut work)?;
let b = child_under(edge.target, *parent, &parents, &mut work)?;
if edge.oriented && b == Some(*id) && a != Some(*id) {
incoming.push(positions[&edge.source].y + sizes[&edge.source].height / 2.0);
}
}
// Do not also chase outgoing boundary neighbours: simultaneous
// swaps in two connected containers can preserve the crossing.
let values = &incoming;
let score = if values.is_empty() {
positions[id].y
} else {
values.iter().sum::<f32>() / values.len() as f32
};
scores.insert(*id, score);
}
for layer in layers.values_mut() {
// First pass starts from canonical alias order; subsequent passes
// retain a deterministic alias tie break, never hash iteration.
if pass > 0 {
layer.sort_by(|a, b| {
scores[a]
.total_cmp(&scores[b])
.then_with(|| names[a].cmp(&names[b]))
});
}
}
groups.insert(*parent, layers.into_values().collect::<Vec<_>>());
}
// Recompute from frozen minima, never add spacing to last pass's size.
sizes = minima.clone();
measure(None, &groups, &headers, &mut sizes, gap_x, gap_y, &mut work)?;
place(
None,
Position { x: 40.0, y: 40.0 },
&groups,
&headers,
&sizes,
&mut positions,
gap_x,
gap_y,
&mut work,
)?;
}
let d = result.diagrams.get_mut(&diagram).unwrap();
for (id, node) in &mut d.nodes {
node.position = positions[id];
node.size = sizes[id];
}
let deltas: BTreeMap<_, _> = original
.nodes
.iter()
.map(|(id, node)| {
(
*id,
Position {
x: positions[id].x - node.position.x,
y: positions[id].y - node.position.y,
},
)
})
.collect();
let translated: BTreeMap<_, _> = projection::translated_routes(project, original, &deltas)
.into_iter()
.map(|r| (r.edge, r))
.collect();
d.routes = original
.routes
.iter()
.map(|route| {
let mut route = translated.get(&route.edge).unwrap_or(route).clone();
if eligible.contains(&route.edge) {
route.waypoints.clear();
route.label = None;
}
route
})
.collect();
if d.nodes.values().any(|n| {
!n.position.x.is_finite()
|| !n.position.y.is_finite()
|| !n.size.width.is_finite()
|| !n.size.height.is_finite()
|| n.size.width <= 0.0
|| n.size.height <= 0.0
}) {
return Err(ModelError("Invalid layered probe geometry.".into()));
}
oa_core::validate_candidate(&result)?;
Ok(result)
}
fn child_under(
mut id: Id,
parent: Option<Id>,
parents: &BTreeMap<Id, Option<Id>>,
work: &mut usize,
) -> Result<Option<Id>, ModelError> {
for _ in 0..=parents.len() {
spend(work)?;
let Some(actual) = parents.get(&id) else {
return Ok(None);
};
if *actual == parent {
return Ok(Some(id));
}
let Some(next) = actual else { return Ok(None) };
id = *next;
}
Err(ModelError("Layered probe containment cycle.".into()))
}
fn ranks(
ids: &[Id],
arcs: &BTreeSet<(Id, Id)>,
work: &mut usize,
) -> Result<BTreeMap<Id, usize>, ModelError> {
let mut remaining: BTreeSet<_> = ids.iter().copied().collect();
let mut ranks: BTreeMap<_, usize> = BTreeMap::new();
while !remaining.is_empty() {
let mut ready = None;
for id in ids.iter().filter(|id| remaining.contains(*id)) {
let mut blocked = false;
for (a, b) in arcs {
spend(work)?;
blocked |= b == id && remaining.contains(a);
}
if !blocked {
ready = Some(*id);
break;
}
}
// Explicit cycle fallback: break the first canonical remaining vertex's
// incoming ranking constraints. Actual relation direction is unchanged.
let id = ready.unwrap_or_else(|| *ids.iter().find(|id| remaining.contains(*id)).unwrap());
let mut rank = 0;
for (a, b) in arcs {
spend(work)?;
if *b == id
&& let Some(previous) = ranks.get(a)
{
rank = rank.max(previous + 1);
}
}
ranks.insert(id, rank);
remaining.remove(&id);
}
Ok(ranks)
}
type Groups = BTreeMap<Option<Id>, Vec<Vec<Id>>>;
fn measure(
parent: Option<Id>,
groups: &Groups,
headers: &BTreeMap<Id, f32>,
sizes: &mut BTreeMap<Id, Size>,
gx: f32,
gy: f32,
work: &mut usize,
) -> Result<Size, ModelError> {
let Some(layers) = groups.get(&parent) else {
return Ok(Size {
width: 0.0,
height: 0.0,
});
};
let mut width = 0.0;
let mut height = 0.0_f32;
for (i, layer) in layers.iter().enumerate() {
let mut lw = 0.0_f32;
let mut lh = 0.0;
for (j, id) in layer.iter().enumerate() {
spend(work)?;
let content = measure(Some(*id), groups, headers, sizes, gx, gy, work)?;
let size = sizes.get_mut(id).unwrap();
if groups.contains_key(&Some(*id)) {
size.width = size.width.max(content.width + 48.0);
size.height = size.height.max(content.height + headers[id] + 24.0);
}
lw = lw.max(size.width);
lh += size.height + if j == 0 { 0.0 } else { gy };
}
width += lw + if i == 0 { 0.0 } else { gx };
height = height.max(lh);
}
Ok(Size { width, height })
}
#[allow(clippy::too_many_arguments)]
fn place(
parent: Option<Id>,
origin: Position,
groups: &Groups,
headers: &BTreeMap<Id, f32>,
sizes: &BTreeMap<Id, Size>,
positions: &mut BTreeMap<Id, Position>,
gx: f32,
gy: f32,
work: &mut usize,
) -> Result<(), ModelError> {
let Some(layers) = groups.get(&parent) else {
return Ok(());
};
let mut x = origin.x;
for layer in layers {
let mut y = origin.y;
let mut width = 0.0_f32;
for id in layer {
spend(work)?;
positions.insert(*id, Position { x, y });
place(
Some(*id),
Position {
x: x + 24.0,
y: y + headers[id],
},
groups,
headers,
sizes,
positions,
gx,
gy,
work,
)?;
y += sizes[id].height + gy;
width = width.max(sizes[id].width);
}
x += width + gx;
}
Ok(())
}
@@ -0,0 +1,192 @@
//! 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(())
}
@@ -0,0 +1,555 @@
//! 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(())
}
+76 -40
View File
@@ -6,7 +6,9 @@ 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;
@@ -420,6 +422,73 @@ 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();
@@ -512,16 +581,8 @@ fn route_diagram_impl(
continue;
};
let stored = authored.get(&edge.id).copied();
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 (custom_suspended, route, attachments) =
effective_route(project, diagram, edge, stored);
let pins = route.map_or_else(Vec::new, |r| r.waypoints.clone());
let obstacles = edge_obstacles(edge, &nodes, &rectangles, &headers);
@@ -559,24 +620,11 @@ fn route_diagram_impl(
});
}
}
let ends = edge_endpoints(project, diagram, edge, source, target, view, attachments);
let (points, pin_lengths, failure) = route_edge(
edge,
&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],
),
&ends[0],
&ends[1],
&pins,
&obstacles,
&previous,
@@ -793,13 +841,7 @@ 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 edge.source == edge.target
&& edge.source_port.is_none()
&& edge.target_port.is_none()
&& a.point == b.point
&& a.stub == b.stub
&& !coincident
{
if !allowed_endpoint_pair(edge, a, b, coincident) {
continue;
}
let estimate = manhattan(a.stub, pins.first().copied().unwrap_or(b.stub))
@@ -823,13 +865,7 @@ fn route_edge(
}) {
continue;
}
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))
{
if !lead_pair_clear(edge, a, b, obstacles) {
continue;
}
let mut points = vec![a.point, a.stub];
+173
View File
@@ -0,0 +1,173 @@
//! 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
@@ -0,0 +1,238 @@
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)
);
}
+77
View File
@@ -498,3 +498,80 @@ 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.
@@ -0,0 +1,151 @@
# 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.
@@ -0,0 +1,38 @@
# #32 candidate critique — 2026-09-25
Read-only adversarial review of `harness/auto-layout-investigation-20260925.md` in the715036e-based isolated checkout, against the source/evaluator map. This critiques candidate choices; no implementation, execution or acceptance is claimed.
## Recommendation
Use the existing explicit **Command::Layout / Auto-layout / Arrange elements** operation for the new automatic behavior. The user specifically asks that operation to replace bends and consider labels/intersections. A second command/UI choice would preserve the obsolete behavior as a competing default without demonstrated need. Deliberately amend its documented contract and focused preservation tests, retain exact Undo, and retain existing ordinary drag/Arrange-next-drag contracts. A new command becomes warranted only if concrete compatibility/user workflows require both automatic policies, not merely because a test currently asserts old behavior.
Prefer comparing candidate1 reset-only against candidate2 layered siblings plus the existing router. No external engine is justified yet. The existing router already creates derived elbows, so reset does not require writing every solver corner as a persisted hard pin. Keep generated corners derived initially; the saved node placement plus remaining explicit attachments determines their repeatable reconstruction.
Recommended explicit Layout route contract: identify eligible visible, non-promoted edges from the **pre-layout projection**, remove their stored waypoints and label override (fraction and offset together), retain source/target attachments and node port anchors. Retain unrelated/hidden/promoted route records with existing equal-delta endpoint-owner translation. Do not call broad Reset routing if that also clears attachments. Preserve stable route-list order and remove an emptied record only under an explicit canonical no-metadata rule. Layout-generated record churn is not progress.
## Blocking design gaps before accepting candidate2
1. **Eligibility must be frozen once.** Visible edges, semantic endpoint-owner placements and promoted endpoints are different sets. Compute the reset set before node movement using projection visibility plus actual owner identity, not “every stored edge” or endpoints merely present in `d.nodes`. A filtered/hidden edge can retain a valid route; a folded edge may be drawn from an ancestor while its own route is suspended. Recomputing eligibility mid-layout risks erasing metadata when visibility/promotion changes. Small experiment: parallel visible/filtered edges, one folded child endpoint, and one both-endpoints-fold-to-same-anchor edge, all with distinctive pins/labels/attachments. Require only declared reset members to change, and retained pins to translate only through the existing owner-delta rule. Unfold/unfilter must reveal the retained custom route.
2. **Two forests are needed conceptually, not two model hierarchies.** The authored projection-parent forest includes folded descendants; the rendered topology may omit them. Reordering only rendered nodes can leave hidden children outside resized parents or leave future expand geometry broken. Conversely, expanding all hidden content for outer layout wastes space and ignores the actual view. Decide visible sibling arrangement versus hidden subtree placement/reservation explicitly. Lift each rendered inter-subtree edge to the relevant direct children at its lowest common ancestor; do not flatten every edge to roots (loses nested ordering) or count the same edge at every depth as independent demand. Small experiment: nested A/B children with crossed exchanges, folded A, external sibling C and a State entry/exit boundary. Check containment/header/port-footer rules before and after expand, with semantic parents/allocations exact.
3. **Idempotence will fail if spacing compounds current sizes.** Current measure uses each authored `node.size` as a lower bound. If label clearance expands a container and the next call adds the same margin again, repeated Arrange grows indefinitely. Label spacing based on previous routed bounds can similarly oscillate. Decide whether current sizes are immutable minima, or may shrink; the latter exceeds today's behavior and needs justification. Compute desired padding from content minima with `max`, not repeated addition to an already padded size. Small experiment: ten consecutive calls on nested long-label/parallel-edge fixtures, comparing full Projects after first vs second and sizes after tenth; repeat after Save/reparse. A two-call-only test can miss alternating period-two layouts.
4. **Cycle/direction policy is not settled by “stable sweeps”.** Some projected edges are undirected; direction may be semantic or merely an endpoint representation. Use directed topology where justified, deterministic SCC treatment for cycles, and explicit undirected ordering inputs. Do not arbitrarily make a Capability/Traceability edge's serialized orientation a mandatory rank. Freeze alias/identity tie rules; crossing sweeps require a stable acceptance tie-break to avoid ping-pong. Small experiment: directed diamond+return, reversed undirected endpoint records, self-loop, parallel/reversed edges and disconnected isolates. Permute input records; independently require identical output for identical IDs and stable quality under UUID changes (not necessarily identical coordinates under reidentification).
5. **Label reset and label-aware spacing need different evidence.** Clearing authored overrides is a reasonable explicit-auto interpretation but must be announced, since issue32 says “take into account” labels, not explicitly erase them. Retain semantic text/typed references; only the target view's override changes. A stale far-away label is a concrete reset fixture; an intentionally constrained attachment/label case tests whether residual collisions are honestly reported. Base715 label widths are scalar estimates, and State title/multiline geometry is known inaccurate without36. Do not tune spacing to claim accurate measured-State acceptance on715. First isolate ordinary/association labels; use conservative declared bounds for experiments, then rerun State B/W/U once36 integrates. Font-free core/API parity forbids quietly using desktop-only font results inside Command::Layout.
6. **Bounded sweeps do not alone bound runtime.** Each complete route evaluation invokes previous-edge interactions, node obstacles and label comparisons; repeated per-sibling trial routing can multiply this cost by nodes×sweeps. Lifting topology naively can multiply edges×depth. Define global deterministic work budgets for candidate ordering/scoring, not just a fixed iteration count, and retain the best valid candidate on exhaustion. Route only a bounded number of whole candidates; cheap crossing surrogates can rank candidates but final acceptance must inspect actual geometry. Small experiment: a fixed family increasing sibling count/edge density/nesting, recording candidate count, comparison/work counters and wall time; include no-edge/isolate cases so they do not pay quadratic routing costs. No hard latency threshold should be fabricated from one machine.
## Input/source/API contract checks
- Clean whole-view Layout should create one reversible model/source transaction. `app.rs` applies a pending property draft before executing Layout, potentially as a separate transaction; do not accidentally promise one Undo reverses both an unrelated draft Apply and Layout. Use a clean-input one-step Undo oracle and a separate valid/invalid pending-draft admission test. Keep diagram UUID remapping, stale selection handling and disabled/pending form policy.
- `prepare_command`/Document/source bundle/REST dry-run must produce the same Project for the same inputs without GUI fonts, caches or selection. A frontend-only rearrangement would fail this. Roundtrip the stored record representation, check unrelated source files/comments remain exact, and recover the exact old source/model with Undo—not merely visually similar positions.
- Keep Allocation Arrange-next-drag, ordinary group translation, semantic ports, reconnect, Hide/show, collapse flags and other diagrams unchanged. A route reset belongs only to explicit Layout. A failed candidate must not clear history or leave a partially reset diagram.
- Native validation later needs visible controls, Fit/export agreement, actual label containment and route readability, plus Save/reopen/Undo. Do not extend the implementation merely to expose a new State Auto-layout control before a demonstrated workflow need; shared State initialization still needs regression coverage.
## Smallest discriminating experiment set
Freeze six hand-built cases before implementation: (A) stale dogleg+far label with fixed attachments, (B) two-container reversed sibling connections with a known zero-crossing witness, (C) nested folded/filtered route-conservation sentinel, (D) cycle/self-loop/parallel/undirected variants, (E) long ordinary/association labels with feasible compact clearance, (F) dense bounded stress. Compare existing Layout, reset-only, and a layered prototype on the same independent vector: invalid overlap/penetration, label collisions, proper crossings, positive collinear overlap, turns, path length/stretch, area and routing warnings. Include ten-call idempotence, exact other-view/semantic conservation, source roundtrip and Undo/Redo.
Candidate2 earns selection only if it materially improves at least B/E over reset-only without regressing the hard invariants or bounded workload. A tie favors the smaller candidate. A nonplanar or contradictory-fixed-port fixture may retain crossings; zero-crossing-by-overlap, giant detours, hidden edges or clipped labels is not a solution. Failure on a named fixture should revise the exact layer/policy implicated, not trigger an automatic wholesale engine dependency.
@@ -0,0 +1,56 @@
"""Compare fixed Project/node/port/endpoint geometry and report routing changes.
Usage: python compare_probe.py OLD_JSONL NEW_JSONL NEW_OUTPUT_JSON
No layout-quality pass is inferred from equal inputs or successful execution.
"""
from pathlib import Path
import hashlib
import json
import sys
old_path, new_path, out = map(Path, sys.argv[1:])
def read(path):
rows = [json.loads(line) for line in path.read_text(encoding='utf-8').splitlines()]
return {row['fixture']: row for row in rows if 'fixture' in row}
old, new = read(old_path), read(new_path)
assert old.keys() == new.keys()
def variants(row):
yield 'before', row['before_project'], row['before']
yield 'baseline', row['after_project'], row['after']
for name in ['reset_only_control', 'experimental_candidate', 'manual_planar_order_witness']:
if row[name] is not None:
yield name, row[name]['project'], row[name]['metrics']
def endpoints(metrics):
return {e['id']: [e['points'][0], e['points'][-1]] for e in metrics['routed_edges']}
keys = ['proper_crossings', 'pairwise_collinear_shared_length',
'nonterminal_pairwise_shared_length', 'unrelated_node_collisions',
'unrelated_edge_node_penetrations', 'label_node_collisions',
'label_label_collisions', 'unrelated_label_stroke_intersections',
'warning_count', 'route_bends', 'route_length', 'drawing_area']
results = []
for name in old:
lhs, rhs = list(variants(old[name])), list(variants(new[name]))
assert len(lhs) == len(rhs)
for (variant, op, om), (other, np, nm) in zip(lhs, rhs):
assert variant == other
fixed = {'project':op == np, 'nodes':om['projected_nodes'] == nm['projected_nodes'],
'ports':om['projected_ports'] == nm['projected_ports'],
'route_endpoints':endpoints(om) == endpoints(nm)}
results.append({'fixture':name, 'variant':variant, 'fixed_geometry':fixed,
'metrics':{key:{'old':om[key], 'new':nm[key]} for key in keys},
'new_point_contacts':nm.get('point_contacts'),
'new_point_contact_details':nm.get('point_contact_details')})
summary = {'old_sha256':hashlib.sha256(old_path.read_bytes()).hexdigest(),
'new_sha256':hashlib.sha256(new_path.read_bytes()).hexdigest(),
'all_projects_nodes_ports_endpoints_exact':all(all(r['fixed_geometry'].values()) for r in results),
'scope':'Fixed-geometry comparison; quality vector retained, no aggregate quality pass.',
'results':results}
with out.open('x',encoding='utf-8') as f:
json.dump(summary,f,indent=2)
f.write('\n')
print(json.dumps({k:v for k,v in summary.items() if k != 'results'}))
for row in results:
if row['variant'] == 'experimental_candidate':
print(json.dumps({'fixture':row['fixture'], 'fixed_geometry':row['fixed_geometry'],
'changed_metrics':{k:v for k,v in row['metrics'].items() if v['old'] != v['new']},
'point_contacts':row['new_point_contacts']}))
@@ -0,0 +1,46 @@
# L results and four-way routing experiment audit
Recommendation: stop tuning these fixtures. L is a useful experimental witness that route alternatives affect sharing, but its small layered benefit and material runtime signal do not presently justify its per-leg preprocessing as a production default. Keep J as the simpler independently motivated scoring correction candidate; decide L only against frozen independent scenes and route-only timing. No production/native acceptance claimed.
## Verified final L result
Primary J06 pin `08656b18bf8934cf264469cf68fc6dea97c15cbb`; L11 pin `e8ec6dbb3160f62476a5557f14605f68959f65fe`. Both recorded offline dev/gnullvm probe commands exit0, source unchanged, failure null. Verified receipt log hashes. Separate raw-output traversal confirms all37 Projects, projected nodes/ports and per-edge endpoint records exactly equal. All nine candidate supported/repeat-input/idempotence/ten-call/JSON-and-single-source-roundtrip results remain true, with unchanged conservation and baseline history checks. Candidate Command/Undo integration remains absent.
J→L changed scalar rows only:
- Original bipartite raw sharing872→724, nonterminal800→652.
- Layered bipartite raw187→176, nonterminal115→104; drawing area175960→165360.
- Original two-container raw/nonterminal54→12.
- Two-container baseline and reset raw/nonterminal18→12 each.
The other32 rows are unchanged in recorded scalar quality metrics. No changed point-contact, proper-crossing, length, bend, warning or collision counts in J→L. Independently comparing full candidate metric objects confirms all nine L layered metrics exactly equal PL, not merely the headline totals. Remaining layered bipartite104 nonterminal shared units still prohibit a solved-traceability claim.
Test10 receipts record135+7+13+18+2+13=188 passed,0 failed/ignored, exit0, unchanged source. J02 and L10 command argv and entire recorded environment dictionaries compare equal. Their routing_geometry test summary elapsed4.30s versus16.43s (~3.82 times, +12.13s); parent reports no concurrent agent compiler. This is a material cost signal, not a controlled routing benchmark: suite runtime includes varied tests and scheduling effects, with no repeated route-only timing. It must not be dismissed by quoting cargo compilation time or presented as an established scaling law.
Verified37 L schematic image hashes/lengths and manifest input hash. Native/glyph rendering was not exercised. Strict Clippy12 was active when assigned and is outside this audit; no outcome inferred.
## Four-way conclusion
All numbers below are raw pairwise shared length; inspect the preceding audits for contacts/area/turn tradeoffs.
| Scene/variant | J | P | P+L | L |
|---|---:|---:|---:|---:|
| Layered bipartite |187|187|176|176|
| Original bipartite |872|730|724|724|
| Baseline/reset bipartite |276|276|72|276|
| Original two-container |54|6|12|12|
| Baseline/reset two-container |18|18|12|12|
P has no layered benefit. P+L's baseline bipartite72 means only common terminal sharing remains, but proper crossings rise0→1, length+24 and area+19392; L alone does not produce that tradeoff. The strongest ordinary two-container sharing result is P6, at an extra bend,12 length units and one T contact. Neither the coefficient nor lanes dominates all vectors. J diamond's isolated improvement remains valid but does not erase its original bipartite regression.
Next scope should be finite and specified before inspecting outcomes: one realistic nested/folded scene, one mixed fan-in/out with a fixed edge-ID permutation, and one modest sparse scene measured by route-only timing and warning/budget counts. Preserve endpoint/model constraints and evaluate traceability, collisions, bends/length/area jointly. Do not silently extend unsupported layered folded behavior into an acceptance claim. Set practical timing and readability criteria before repeating improvement. If L does not show proportionate independent benefit, omit it; avoid adding configuration/architecture solely to retain every experiment. The explicit Layout reset policy and ordinary input/Undo/Save lifecycle are still separate implementation work.
## Evidence identities
J06 output `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
L11 output `64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d`.
L11 result.json `feee84c2fde115c22ea865033ff2d136da2aace1f1c8a7423c8add11358366a8`.
L comparison JSON `e1e23e6c2a50cd384457bb061d5b70a740f586f42767164fad9703ecbb4096a8`.
L contact audit JSON `6f6cc674c27d3f43001fe1751ef3b09332caa9ddca396759f5525f811cbe1aaf`.
Read-only audit of completed records; no build/probe/helper rerun, source edit or publication. Earlier independent J/P/PL source/results notes retain grid-axis, subdivision-score, capped retained coordinates versus unbounded preprocessing, stable-edge-order and approximate-label limitations.
@@ -0,0 +1,20 @@
# Bounded L lane-candidate source review
Reviewed routing.rs SHA256 `af5995af10c8e3b30c5c6fb776a2ac2678eeef59dd58eb0cdb3d5c62cd153f1b` before parent formatting. Static inspection only; no builds or source edits. No blocking implementation finding for the finite nine-fixture P+L / J+L probe comparison.
The code retains all sorted base obstacle coordinates and adds at most64 unique extras EACH axis (128 total), filters nonfinite generated values, deduplicates before ranking, then ranks distance from the start/end axis interval, distance from its midpoint, and numeric value. Final lists return to coordinate order. It derives perpendicular offsets only from nondegenerate settled other-edge segments. The current edge's earlier legs/source stub still contribute occupied scoring but do not generate lanes. Fast/grid receive the identical per-leg RoutingSpace; obstacles, endpoints, authored pins, terminal joins and fallback remain unchanged.
Three new tests cover80 retained base coordinates plus64 extras per axis, previous-segment reorder/duplication invariance, nearest-interval/midpoint selection and nonfinite rejection, and direct calls to fast/grid sharing the same parallel-lane witness. The latter expects min(direct cost,272) and supports both coefficients. No test success is inferred before execution.
Test-scope caveat sent to parent: the existing `unspecified_continuation_keeps_intermediate_leg_choice` test deliberately hardcodes baseline coefficient0.12, path choice and cost255.52. At P3, the shared penalty caps80 and the alternative is cheaper; a whole private suite at P3 can fail that baseline-policy assertion. Preserve the result honestly; restore0.12 for baseline-suite claims or explicitly distinguish experimental tests. This does not block a diagnostic P+L probe.
Limits relevant to interpreting results:
-64 bounds retained coordinates, not scan/sort work. Every endpoint-pair/leg constructs candidates from all previous segments; this preprocessing is outside the search-step budget. No large-scene performance guarantee.
- Added coordinates can make the grid exceed65536 cells even when its original grid fit. Existing exhaustion warning/fallback is the evidence to inspect, not something to suppress.
- Grid scoring is coordinate-subdivision-sensitive: strict-interior crossing tests can miss contacts at inserted grid vertices, and per-segment capped overlap charges can change with subdivision. Therefore a grid result can change due to scoring partition as well as newly offered parallel lanes. Keep independent contact/shared-interval metrics authoritative for quality observations.
- Rank uses one axis and does not filter segment extent on the other; remote lanes can consume the cap. This deterministic heuristic is not proof of optimal lane coverage. The router still uses a feasible fast path before grid, two-axis rather than signed-direction search state, stable sequential edge order, and local hard-pin legs.
Required experiment interpretation: compare P+L to P and J+L to J with exact Project/node/port/endpoints, all quality metrics and warning counts. Retain label collisions, T/bend contacts, length/turn/area regressions; fewer shared units alone is not acceptance. No broad production or native readability conclusion follows from this finite source review.
Current formatted routing SHA256: 3a8af7a44f8f32bd9fb94dddd9184fafcf64c93c510025169c62958566bbaedf. Reread formatted lane construction: filtering/ranking/cap semantics agree with reviewed candidate. No mechanical original-byte whitespace comparison claimed. Parent plans exactly the three lane-filtered private tests for P+L, then restores0.12 for the full baseline suite; that appropriately separates the baseline-policy assertion noted above.
@@ -0,0 +1,35 @@
# P+L results independent audit
P+L demonstrates that additional lanes can remove one scene's nonterminal overlap, but adds a proper crossing and gives only a small layered improvement. It does not yet justify adopting the extra heuristic as a general production default. Static record audit only; no reruns, builds or source edits.
Compared P07 `3d7adff923dee5bed54dfdccc119dbee0c7c2773` with PL09 `d0be9ff0674373fcf9623daf62bbf50dad02c4df`. Both probe receipts exit0, failure null, unchanged source; all logged hashes independently checked. Separate raw-output traversal confirms all37 Projects, projected nodes/ports and route endpoint records exact. All nine candidate support/repeat/idempotence/ten-call/roundtrip results remain true; conservation and baseline Command::Layout history checks match P. Candidate Undo integration remains untested.
Test08 actually ran `cargo test --locked --offline -p oa-core --lib lane`: five passed,130 filtered, zero failed/ignored. This is three new routing lane tests plus two existing scenario-layout tests, not a whole core-suite pass.
All changed numeric-vector rows, P→PL:
| Scene/variant | Sharing raw / nonterminal | Other changes |
|---|---|---|
| bipartite before |730→724 /658→652|contacts10→9; bends5→4; length2076→2064|
| bipartite baseline |276→72 /204→0|proper crossings0→1; contacts6→5; length3284→3308; area300576→319968|
| bipartite reset |276→72 /204→0|same changes as baseline|
| bipartite layered |187→176 /115→104|area175960→165360; contacts9 unchanged|
| two-container before |6→12 /6→12|contacts3→2; bends5→4; length1524→1512|
| two-container baseline |18→12 /18→12|no other scalar change|
| two-container reset |18→12 /18→12|no other scalar change|
Remaining30 rows unchanged; eight other layered vectors unchanged. No new label-collision or warning-count changes appear. The baseline/reset proper crossing is a real quality tradeoff, not an automatic failure: a visible isolated crossing may be easier to trace than coincident routes. Conversely, zero proper crossings in the layered scene still accompanies104 nonterminal shared units. Two-container original sharing doubles6→12 despite fewer contacts/turns. No single scalar orders all these results.
Viewed the baseline and layered bipartite PNGs. Baseline channels separate except for the isolated crossing; layered channels retain shared horizontals. Verified all37 offline image hashes/lengths and manifest input binding. These are schematic core geometry, not actual font/native rendering or a user traceability test.
Performance/complexity: probe command elapsed approximately67.1s(P) and69.7s(PL), but these cargo invocations include compilation; they are not comparable routing benchmarks and establish no overhead bound. The new code scans/sorts all prior segments for each endpoint-pair/leg;64-per-axis limits retained coordinates, not preparation work. It can expand the grid past its existing cell cap. Grid crossing/overlap scoring also changes under coordinate subdivision. None of these limitations is resolved by the tiny fixture set.
Recommendation: finish the already-declared J/P/PL/L grid and stop coefficient/lane-spacing tuning on these fixtures. Retain L as an experimental option unless the final comparison supplies stronger value. The next useful acceptance scope is a frozen, modest set of independent scenes chosen before results: one realistic authored diagram with nested/folded content, one mixed-direction fan-in/out, and one moderately sized sparse diagram for routing time/budget behavior, including a fixed edge-order permutation. Choose a preferred traceability tradeoff explicitly; do not add architectural hooks merely to preserve this heuristic. Prioritize the explicit Layout command/reset contract and production integration lifecycle once a maintainable geometry choice is selected. No #32 closure or native readability acceptance follows here.
Bindings:
- P output SHA256 `13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
- PL output `04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd`.
- PL result.json `538aa79bcedd4cf646c63d5309ec738be4676e2045715db1035a4f334a536117`.
- PL comparison JSON `81f57e651a8840aaaeacc085df2eb90174b2e494182f6cd40ccd6d50e7bb531e`.
- PL contact audit JSON `60ce7e9735ceef50a92d29a0414aafe3d8fb6174dab99eff6397e2abc88e0afa` (inspected as independent worker evidence, not rerun here).
@@ -0,0 +1,26 @@
# P overlap-penalty experiment independent audit
Confirmed the reported finite result. Static read-only audit; no build, probe rerun, source edit or GUI action. P does not improve any of the nine layered candidate metric vectors and is not a demonstrated solution to their remaining shared routes.
Primary comparison: J06 `08656b18bf8934cf264469cf68fc6dea97c15cbb` versus P07 `3d7adff923dee5bed54dfdccc119dbee0c7c2773`. Inspected the latter commit: only routing.rs changes, overlap coefficient0.12→3.0 plus an experiment comment; cap80 remains unchanged. Both recorded `cargo run --locked --offline -p oa-core --example auto_layout_probe` receipts are Windows gnullvm/dev, exit0, inputs unchanged, failure null. Independently verified every log hash in both receipts.
Independent traversal of the raw outputs confirmed all37 variant Projects, projected nodes, projected ports and emitted route endpoint records match exactly. All nine layered candidates retain supported=true, repeat-input exactness, idempotence, passes2–10 equal first/previous, exact JSON/single-source roundtrips and identical conservation results. The authored-detour route-reset exception remains intentional. Baseline Command::Layout history/Undo checks remain identical; this is still not candidate-command Undo evidence.
Only two variant rows change numeric metrics:
| Original/before scene | Raw sharing J→P | Nonterminal sharing J→P | Bends | Length | Point contacts |
|---|---:|---:|---:|---:|---:|
| crossed_bipartite |872→730|800→658|4→5|2064→2076|9→10|
| two_containers_reversed_children |54→6|54→6|4→5|1512→1524|2→3|
Each extra contact is classified as a T contact in the separately generated independent interval audit: bipartite T3→4 and two-container T1→2; proper crossings remain0. Lower shared length therefore comes with one additional bend,12 length units and one additional point contact in each scene. Bipartite returns to the pre-J shared-length total; this does not establish trace readability. All baseline/reset rows, manual witness and nine layered scalar vectors are unchanged. Exact model/endpoint invariants do not imply identical polylines.
Evidence identities:
- J06 raw output `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f` (also identical to J03 output).
- P07 raw output `13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
- P07 result.json `6149122d05d77e02b463edb3dd359b06786bc4468c27d8cd625cbc1bc80c9894`.
- P comparison JSON `9f228fbe78e1888c5d93e87dddd8d2effc01bab723929a87423c61e23f5cad66`.
- P independent contact audit JSON `6f4add5c81f6d16c45efabbefd9e36c9beb637b6823993f0d51adc3e20485ad9`. Its recorded definitions and counts were inspected; this reviewer did not execute that helper again.
Recommendation: archive P as a bounded negative result for the layered overlap objective, preserving the two ordinary-scene tradeoffs. A predefined bounded lane-candidate experiment can now test whether available route geometry, rather than this single coefficient, limits improvement. Retain the same Projects/endpoints and all quality metrics; do not tune indefinitely against these nine fixtures or claim general quality/native acceptance. The cap, sequential edge order, fast-path preference, axis-only grid state and estimated label bounds remain limits.
@@ -0,0 +1,47 @@
# #32 bounded automatic-layout probe
Prepared `crates/oa-core/examples/auto_layout_probe.rs` in `.local/auto-layout-20260925` against reference source `715036e132677dd2bc2fb37ed316d93dc9987aec`. No production edits, compiler, Cargo, GUI or Gitea operation by this evaluator. Rustfmt parsed/formatted only the owned main example (`skip_children=true`). The separately owned `auto_layout_probe/layered.rs` is imported through its agreed `candidate(&Project, Id) -> Result<Project, ModelError>` interface; the evaluator does not use candidate internals to define fixtures, geometry metrics or expected conservation.
## Execution and output
From the worktree, in the parent's configured exclusive Windows toolchain environment:
```powershell
cargo run --locked --offline -p oa-core --example auto_layout_probe > auto-layout-probe.jsonl
```
The parent has `.local/run-auto-layout-check-20260925.py` for pinned receipt-based execution. Prefer that for recorded evidence; its source hash/commit must identify the actual build. The example's `reference_source` metadata is the investigation baseline, not a runtime attestation of checkout identity. Stdout is JSON Lines: one metadata/self-check record and nine fixture records. No output files, network calls or UI operations are performed by the example. Errors/unsupported candidates are explicit fields, not quality passes. There is no aggregate score or threshold; a zero metric is not a readability or hard-safety certification.
Each fixture emits the original and current `Command::Layout` Projects and real projected/routed geometry. It also emits the same observations for a **reset-only control applied after existing Layout**, and for the separately implemented experimental candidate invoked on the original Project. The control clears only waypoints and label placement on visible routed edges whose geometry is not suspended/promoted, retaining endpoint attachments, hidden/promoted records and empty route records. The candidate does not determine this control. Ten successive existing Layout calls and ten successive candidate calls are each compared with their preceding and first result, stopping with an explicit error if needed. Candidate identical-input repeat and one further application are also compared separately. Reset eligibility is measured after baseline Layout; the candidate freezes it before Layout. These all-visible fixtures do not change visibility, so broader eligibility-equivalence claims are deferred.
## Declared fixtures
1. Four-node flat chain, initially left to right.
2. Seven-node chain, initially left to right, exposing four-column row wrapping if present.
3. Diamond with branch/join semantics and declared two-level positions.
4. Crossed bipartite ordering, including both straight and crossed pairings.
5. Parent Function with two child Functions, internal exchange and exchange to an outside Function.
6. Two-node authored high detour with a far label offset; reset-only isolates stale constraint cost.
7. Two-node exchange with explicit source-Left0.3 and target-Right0.7 port anchors.
8. Two parent Functions, each with two children, and reversed inter-parent pairings. A separate predeclared witness swaps only right-child y positions, aligning each source with its target. Its real routing is measured; no zero-crossing result is assumed.
9. Three Functions with long ordinary exchange names, including a bypass; the actual existing summary/name excerpt bounds are observed.
Project, diagram, Function, placement, relation and automatically created port UUIDs are remapped to stable IDs in creation order. Port aliases are reset explicitly. Names and other aliases are unique per fixture, avoiding random-ID tie dependence. The fixture Projects in output allow independent repetition and offline visualization; projected node rectangles/ports and per-edge routed point sequences/label rectangles are also included.
## Metric definitions and exclusions
- **Proper crossings:** unique intersection locations per distinct edge pair, interior to both straight segments. Locations deduplicate at0.0001 world units. Segment endpoints, bend contacts, T junctions and collinear overlaps are excluded from this count. Raw crossings remain the primary count. A separate nonterminal count subtracts only contacts within `PORT_STUB` of a physically equal endpoint with the same projected owner, where both tested segments are terminal. Entire compacted first/last segments are never exempt.
- **Shared runs:** summed pairwise collinear overlap length, reported separately from crossings. Raw length is primary. Common exact endpoint terminal overlap gets a separately reported exemption bounded by `PORT_STUB` per common endpoint, capped by the overlap. Three overlapping edges contribute three pairwise overlaps; retraced segments may contribute multiplicity. This is not union length.
- **Unrelated node collisions:** positive rectangle intersection area for distinct nodes; ancestor/descendant pairs are exempt from this count. No inferred intent is attached to a reported collision.
- **Label/node collisions:** positive intersection of real routed label bounds with projected node rectangles, including endpoint nodes. A label wholly inside an endpoint ancestor's *body below the header* is exempt; overlap with its header remains reported. Ordinary header height is64; dedicated State height uses the core helper. Border crossings are retained. These conservative boxes are not glyph measurements.
- **Edge/node penetration:** per edge/node pair, positive clipped segment length in unrelated node interiors. Endpoint-owner nodes are exempt; endpoint ancestors contribute only their header obstacles, so intentional passage through container bodies/boundaries is not counted. This does not detect re-entry into an edge's own endpoint node.
- **Label/stroke intersection:** positive clipped length of another edge's stroke inside a label rectangle, one record per label-edge/stroke-edge pair. Own-edge strokes are excluded; an intentional anchor/label association is not declared a defect. Stroke thickness, arrowheads and antialiasing are unmodeled.
- **Other observations:** actual routing warnings and details; routed total length; direction-changing bends including reversal; total drawing bounding-box area (including labels/nodes); real node/port/edge geometry. Area is scale-sensitive and is not minimized at the expense of crossings or readability.
Tiny analytic assertions check proper crossing versus endpoint contact, collinear overlap versus separated lines, rectangle contact, and line/interior clipping. They will run with the example, but have not been executed by this author. Geometry tolerance is0.0001 world units, while proper-intersection parameter/parallel checks use1e-9.
## Conservation and limits
The current command is exercised through `Session`, with exact one-step Undo/Redo and history/no-op checks. Full JSON decode and formatted single-source parse round trips are compared to the complete Project before/after; these do not prove original multi-file comments/byte preservation. Semantic records, target-view nongeometry fields, other views, per-node identity/visibility/port anchors and authored routes are reported separately. Reset/candidate route equality may intentionally be false and must be assessed against their stated reset policy, not silently treated as semantic loss.
Folded/filter/hidden-route preservation is implemented in the reset eligibility check but not independently falsified by these nine fixtures. Dedicated State #36 native typography, dense stress, cycles, disconnected large sets, non-planar crossing lower bounds, self-crossings, self-loops, full stroke geometry and interactive cognitive load are absent. The candidate may explicitly reject unsupported cases. No algorithm can promise crossing-free output for arbitrary non-planar graphs; the paired-container witness only establishes a concrete alternative ordering to examine. Use vector observations and the output geometry to diagnose mechanisms before selecting a candidate; this is a bounded experiment, not a production layout-quality framework or native acceptance.
@@ -0,0 +1,27 @@
# #32 first diagnostic probe review
**No blocking finding for compiling/running the current finite experiment.** This is a source/evaluator-validity review, not production acceptance or a claim the candidate improves layout. Nine small deterministic FunctionalDataflow fixtures support a bounded comparison; later scope gaps should not delay this run. No compiler, GUI, helper, source edit or Gitea operation performed.
Reviewed snapshot SHA256: auto_layout_probe.rs `72d850fdd9aad65788004949380c28cba48a0c2be3dc28f3aef3900c7f8724c7`; auto_layout_probe/layered.rs `bda9a59968b4b0e284e8e1393eb86c90cdf0d856d5f9830ae3c6fc0043df839a`. The evaluator worker is separately finalizing candidate repetition reporting; later edits require a scoped diff check, not relabeling this reviewed snapshot.
## Evaluator validity
Raw strict-interior segment crossings and pairwise collinear shared length are primary outputs, with crossing coordinates deduplicated per edge pair. Endpoint sharing is not exempted wholesale: secondary figures subtract only bounded common physical tip lengths. Node/header, label/node, label/label and unrelated stroke/label measurements remain separate. Analytic primitive checks cover a proper crossing, endpoint touch, collinear overlap, disjoint parallel segments, rectangle touch and inside-length boundary. Complete before/after models and routed points are emitted, permitting independent examination beyond scalar totals. No quality threshold or automatic overall-pass field promotes a poor drawing to acceptance.
Fixture IDs are normalized before use; semantic port IDs/aliases are also stabilized. The manual reversed-child witness is separately authored and measured, not generated from candidate output. It must still be read as a witness with its reported validation/geometry, not an asserted universal optimum. Standard parse/JSON roundtrip and old-Layout history checks are meaningful within their named scope.
## Actionable limitations to retain when interpreting this run
1. **Reset control eligibility:** reset_effective_routes receives the already arranged Project, whereas layered candidate freezes its eligible set before Layout. For these all-visible, uncollapsed fixtures, Layout does not change membership/promotion, so this does not invalidate the current comparison. Freeze the original eligible IDs for future folded/filtered cases; do not generalize current equivalence.
2. **Conservation granularity:** semantic/other-view/node-metadata checks are independent and useful. target_view_nongeometry_exact restores all routes and layout before comparing; authored_routes_exact will intentionally become false. Those fields do not separately prove attachment preservation, invisible-route retention or a no-change layout field. Add targeted comparisons before making those claims on future fixtures. The current prototype source copies original route records and only clears eligible waypoints/labels, then translates retained routes, so no observed source-level violation was found here.
3. **History scope:** undo_exact/one_step_undo/redo_exact exercise existing Command::Layout through Session only. The layered candidate is a pure Project transformer, not an integrated command and has no tested operation/history lifecycle. Its repeat-same-input and second-call comparison are useful; ten-call candidate stability was pending in this snapshot. Do not describe baseline ten_layout_calls as candidate stability.
4. **Metric coverage:** strict proper crossings deliberately exclude T contacts and intersections at segment bends; pairwise shared length counts segment-pair traversal multiplicity, not geometric union length. No candidate should be selected solely by one scalar if it shifts crossings into uncounted touches. Endpoint-owner interiors are excluded from unrelated-edge penetration, and label/stroke excludes its own edge. These are declared definitions, not proof of complete route validity. Association-end labels, actual glyph ink, State multiline measured bounds and port labels are not covered by current primary label metrics. Current nine fixtures contain functional exchanges, so these omissions do not corrupt their narrow comparison.
5. **Fixture coverage:** all current fixture families are small SA FunctionalDataflow cases. Other-view exactness is vacuous where only one view exists; folding, filtering, omitted-node, State, Allocation, Scenario, undirected cycles, dense scaling, UI admission and multi-file source conservation are not established. Preserve these gaps explicitly rather than broadening the initial run unnecessarily.
## Prototype source risks the experiment should expose
The candidate preserves semantic records and route-list order, retains attachments/port anchors, rejects folded/omitted topology explicitly, and uses stable alias/ID order, deterministic cycle fallback, a graph limit and counted ordering work. Derived corners are not persisted as hard pins. No product file is replaced.
Three passes use frozen per-call minima, but those minima come from baseline Layout using the input's existing sizes; cross-call size ratcheting remains possible and should appear in repeated full-Project comparison. Global maximum label width controls every sibling gap, so one long label may balloon unrelated layout area. Incoming-neighbor ordering can improve the reversed-container fixture without proving general crossing reduction; undirected edges do not constrain ranks/order. The work budget excludes existing projection/routing work and several collections, so it bounds selected prototype loops, not total CPU complexity. With current small fixtures these are diagnostic candidate weaknesses, not reasons to prevent the run.
Interpret a failed invariant, growing repeated layout, worse collisions or huge area as evidence against this prototype. Preserve errors and unsupported statuses; do not use successful process exit as layout-quality acceptance. Decide further work from the produced geometry and independent metric vector. Production integration, complete command/source/API/history behavior, native readability and broader issue32 acceptance remain separate.
@@ -0,0 +1,75 @@
"""Render recorded probe geometry for inspection; this is not a desktop screenshot.
Usage: python render_probe.py PROBE_STDOUT_JSONL NEW_OUTPUT_DIRECTORY
Uses one scale across every result for each fixture; input geometry is unchanged.
"""
from pathlib import Path
import hashlib
import json
import sys
from PIL import Image, ImageDraw, ImageFont
def geometries(value, name=""):
if not isinstance(value, dict):
return
if "routed_edges" in value and "projected_nodes" in value:
yield name, value
return
for key, child in value.items():
yield from geometries(child, f"{name}.{key}".strip("."))
source, output = map(Path, sys.argv[1:])
output.mkdir(parents=True, exist_ok=False)
font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", 13)
files = []
for line in source.read_text(encoding="utf-8").splitlines():
item = json.loads(line)
fixture = item.get("fixture")
if not fixture:
continue
variants = list(geometries(item))
if not variants:
continue
largest_width = max(g["drawing_bounds"]["size"]["width"] for _, g in variants)
largest_height = max(g["drawing_bounds"]["size"]["height"] for _, g in variants)
scale = min(1.0, 1140 / max(1, largest_width), 690 / max(1, largest_height))
for name, geometry in variants:
canvas = Image.new("RGB", (1200, 800), "white")
draw = ImageDraw.Draw(canvas)
origin = geometry["drawing_bounds"]["position"]
def point(position):
return (30 + (position["x"] - origin["x"]) * scale,
70 + (position["y"] - origin["y"]) * scale)
def rectangle(position, size):
x, y = point(position)
return x, y, x + size["width"] * scale, y + size["height"] * scale
draw.text((20, 12), f"{fixture} / {name} | geometry only, not native UI", font=font, fill="black")
draw.text((20, 32), f"Fixed fixture scale {scale:.4f}; text below identifies bounds, not glyph measurements", font=font, fill="black")
for node in sorted(geometry["projected_nodes"], key=lambda n: (n["depth"], n["id"])):
box = rectangle(node["position"], node["size"])
draw.rectangle(box, fill="#eef2f6", outline="#687787", width=1)
draw.text((box[0] + 3, box[1] + 3), node["id"][-5:], font=font, fill="#334155")
for edge in geometry["routed_edges"]:
points = [point(p) for p in edge["points"]]
if len(points) > 1:
draw.line(points, fill="#245c88", width=2)
label = edge["label"]
if label["text"]:
box = rectangle(label["position"], label["size"])
draw.rectangle(box, outline="#ad5715", width=1)
target = output / f"{fixture}-{name.replace('.', '-')}.png"
canvas.save(target)
files.append({"name": target.name, "bytes": target.stat().st_size,
"sha256": hashlib.sha256(target.read_bytes()).hexdigest(), "scale": scale})
(output / "manifest.json").write_text(json.dumps({
"input_sha256": hashlib.sha256(source.read_bytes()).hexdigest(),
"renderer_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
"scope": "Offline schematic of recorded core geometry; no native or font-rendering acceptance.",
"images": files}, indent=2) + "\n", encoding="utf-8")
print(f"Rendered {len(files)} geometry records without modifying the probe output.")
@@ -0,0 +1,66 @@
# #32 automatic arrangement: bounded research
Prepared 2026-09-25; local research, not an accepted design or implementation review. No compiler, GUI, helper, or remote mutation was run. Primary sources were read online. Local source spot-check: clean `.local/auto-layout-20260925`, commit `715036e132677dd2bc2fb37ed316d93dc9987aec`. Parent owns current implementation mapping and contract selection.
The user needs Arrange to generate/remove bends, reduce connection intersections, and account for connection labels, while retaining meaningful nested containment/deployment. A useful solution therefore needs coordinated node ordering, space allocation, routing, and label placement. Merely sorting boxes or clearing existing waypoints cannot establish success.
## Verified precedents and their limits
**Capella workflow.** Capella 7 release notes document Layout Children, temporary movement of pinned elements, and renaming Arrange All/Selection to Layout All/Selection. This supports making operation scope and preservation of manual organization explicit. It does **not** establish that Capella uses ELK as its default engine. [Official Capella 7 notes](https://github.com/eclipse-capella/capella/wiki/Release-Notes-7.0.0).
**Sirius workflow.** Its user guide describes avoiding overlap, fitting containers around contents, attempting fewer edge crossings, and preserving pinned locations. Layout Children operates at the immediate level. A selected container can have its contents arranged while its location remains fixed. The guide also describes simplifying an unpinned edge between pinned endpoints. However, its pinning section and later toolbar section disagree about edge pinning support; do not copy that ambiguity into ARCADIA's contract. [Sirius user guide](https://eclipse.dev/sirius/doc/user/diagrams/Diagrams.html). Sirius documents configurable default/composite and ordered-tree layouts, with ELK as an additional integration described as experimental. Availability of that integration is not evidence of a particular Capella installation's behavior. [Sirius layout configuration](https://eclipse.dev/sirius/doc/specifier/diagrams/Diagrams.html).
**ELK capabilities.** ELK Layered explicitly supports orthogonal routing, ports, labels, compound graphs, and cross-hierarchy edges with suitable configuration. [Algorithm reference](https://eclipse.dev/elk/reference/algorithms/org-eclipse-elk-layered.html). `INCLUDE_CHILDREN` allows a joint run through descendants; the root default otherwise separates children. Independent child layout is therefore not equivalent to globally considering connections across nested containers. [Hierarchy handling](https://eclipse.dev/elk/reference/options/org-eclipse-elk-hierarchyHandling.html). Port constraints distinguish free placement, fixed side/order/ratio, and fixed position. [Port constraints](https://eclipse.dev/elk/reference/options/org-eclipse-elk-portConstraints.html).
The authors describe a Sugiyama-family layered algorithm, constrained barycenter crossing minimization, size/port-aware coordinate assignment, and separate support for compound graphs and disconnected components. These are heuristics with configurable priorities, not a guarantee of globally minimal crossings. [ELK authors, GD 2024](https://drops.dagstuhl.de/storage/00lipics/lipics-vol320-gd2024/LIPIcs.GD.2024.56/LIPIcs.GD.2024.56.pdf).
**Routing is a distinct problem.** Wybrow, Marriott, and Stuckey describe orthogonal visibility graphs, A* route search, and ordering/nudging of shared segments. Their bend/length optimality statement concerns individual routes under their model, not joint optimal placement of all nodes, labels, and connectors. [Orthogonal Connector Routing, GD 2009](https://people.eng.unimelb.edu.au/pstuckey/papers/gd09.pdf). libavoid exposes penalties for crossings, segments, cluster crossings and shared paths, plus endpoint direction constraints. It supplies routing rather than a complete node arrangement solution. [libavoid API](https://www.adaptagrams.org/documentation/namespaceAvoid.html).
## Materially different approaches
| Candidate | Practical proposal for this project | Main advantage | Main risk / decisive falsifier |
| --- | --- | --- | --- |
| Native Rust layered arrangement + existing router | Build a bounded, deterministic placement pipeline over the projected hierarchy; reserve measured label space and improve routes after placement. | Best match to Rust preference, existing model/history, and deployment; reuse current geometry. | Nested cross-boundary routes and label congestion make a supposedly small implementation grow. Reject if the finite compound fixtures require ad hoc per-diagram exceptions or cannot reduce known avoidable crossings. |
| ELK Layered through elkjs | Translate one immutable projected graph to ELK JSON, run a pinned bundled JS engine off the UI thread, validate results, apply a presentation transaction. | Mature joint treatment of ports, labels, layering and hierarchy. | Adds runtime/distribution/adapter cost. Reject if exact port semantics, nested coordinates, measured label boxes, bounded cancellation, or Windows/Linux packaging cannot be demonstrated. |
| Preserve nodes; improve routes and label locations | Use existing Rust routing plus bounded rerouting/order search, or investigate libavoid through FFI. | Least disruption to the user's spatial organization; useful separate Reroute command. | Cannot untangle crossings imposed by node/port ordering. Insufficient as the sole Arrange implementation if an order swap solves a fixture it cannot improve. |
elkjs is the official JavaScript form of ELK's layout algorithms, consumes/returns graph geometry, and supports worker execution. Using the distributed JavaScript does not require a Java runtime. A Rust embedding still needs an explicitly selected JS runtime or packaged process; compatibility, footprint, cancellation and licensing must be checked in a bounded spike. It is not a Rust library or a ready Iced integration. [elkjs repository and API](https://github.com/kieler/elkjs).
Graphviz is a possible comparison baseline, not my preferred default: its current official `splines=ortho` documentation explicitly says this routing does not handle ports or, for dot, edge labels. That limitation directly intersects this task. A separate router/label solver could repair the integration, but removes much of its simplicity. [Graphviz splines](https://graphviz.org/docs/attrs/splines/). Force/stress layout is another possible overview style, but I would not spend the first experiment on it: engineering flow direction, nesting and endpoint constraints still need substantial machinery afterward. This is a fit judgment, not a claim those algorithms cannot be extended.
## Proposed minimum contract, independent of engine
1. **Operate on diagram presentation.** Preserve semantic identities, relation direction, containment/deployment, port identity and connectivity, node/edge membership, and label text. Layout cycle breaking must never reverse the actual model relation. Projected parentage, not an independently guessed semantic tree, defines nesting. Hidden/collapsed content must have a declared policy; do not silently expose it.
2. **Define scope before implementation.** Initial whole-diagram Arrange is simpler than arbitrary selection. If selection is included, decide whether a container means its immediate children or its full subtree, whether it can grow, and how boundary-crossing edges update. Outside nodes remain fixed. Do not infer support for selection from a whole-graph solver.
3. **Define replaceable geometry.** Explicit Arrange may replace the in-scope route waypoints, creating useful bends and removing redundant ones. Decide independently whether authored endpoint attachments and authored label placement are preserved or reset. Recommended initial rule: preserve semantic/fixed attachments; authorize replacement of bend geometry; treat preserved label boxes as constraints. Do not retain stale absolute label offsets accidentally after wholesale rearrangement. Parent must settle this user-visible policy.
4. **Measure before arranging.** Supply visible node dimensions, headers, port/row areas, label rectangles and clearance in world units. Use the same prepared text and measurement as painting, including multiline labels and fallback glyphs. Feed label occupancy into spacing/routing, then validate the final rendered geometry. Fitting labels only after arranging boxes can recreate collisions.
5. **Atomic application.** Return a candidate presentation delta, validate it, then create one Undo entry. Failure/cancellation leaves the model unchanged. Undo restores complete prior geometry; Redo and save/reopen reproduce the result. A stale asynchronous result must not overwrite edits made since its input snapshot.
6. **Quality, not an impossible universal promise.** Require no invalid geometry, prohibited node/header penetration, or lost constraints. Minimize avoidable crossings, label collisions and shared-path ambiguity before compactness and bend count. Preserve a satisfactory baseline when candidates are worse. Hard constraints may make a zero-collision drawing impossible; report the residual rather than claiming success from a cost scalar.
The local spot-check explains one important seam: `crates/oa-core/src/session.rs::layout` already obtains `projection::parents`, recursively sizes nested nodes and rejects Scenario geometry. `routing.rs` explicitly distinguishes persisted authored pins from bounded derived routes. Generated bends need not all become persisted manual pins: persist the chosen presentation change according to a declared regeneration policy. The #36 successor's measured State labels must be reconciled when integrating; this base predates it. No claim about uninspected callers or final API follows from this spot-check.
## Native Rust candidate: finite algorithm experiment
This is a proposal, not an implementation prescription. Build a temporary layout graph with stable IDs, measured boxes, containment, real port constraints and typed edges. Determine feedback edges for cycles without modifying semantics; assign layers; insert temporary long-edge/label placeholders; perform a fixed number of alternating barycenter/median sweeps with adjacent swaps accepted only when crossing cost improves; assign non-overlapping coordinates. Lay out children with explicit boundary connection ordering and reserve parent headers/port areas. Bottom-up subtree packing alone is a baseline, not proof of cross-hierarchy quality.
Route orthogonally around the resulting obstacles, with penalties for bends, crossings and excessive shared paths. Place measured labels in reserved corridors; if conflicts remain, permit a bounded spacing/rerouting pass. Remove duplicate and collinear intermediate vertices. Keep separate metrics for edge crossings, shared-path length, label collisions, bends, area and displacement so a shorter route cannot disguise a newly unreadable diagram. Stable tie-breaking, bounded passes and retaining the best valid candidate limit oscillation and cost. Compare this candidate against the same finite fixtures processed by elkjs before investing in a general framework.
## Falsifiers and finite milestones
**First: freeze the evaluator and geometry policy.** Six small fixtures are enough to expose foundational errors: (a) a two-layer order swap with a known crossing-free solution; (b) a diamond plus cycle/self-loop; (c) a two-level OA containment graph with internal and cross-container connections; (d) SA deployment nesting with fixed semantic ports and high-degree fan-out; (e) long/multiline labels in a tight corridor; (f) disconnected components, collapsed content and an already tidy layout. Include one route needing added bends and one needing removed bends. If scope excludes any fixture feature, state that before scoring.
Count proper interior intersections between distinct routed edges separately from collinear overlaps. Exclude common endpoint contact, but do not exempt edges merely because they share a source: an intersection elsewhere still counts. Count label-label and label-unrelated-edge/node intersections; intentional own-edge label contact and container background containment need specific exemptions. Check allowed container boundary passages rather than counting every containment-border crossing as an error. Record scores on final routes, not only straight-line layer proxies.
**Second: choose using measured results.** For the known solvable fixtures, demand the known crossing/collision target, semantic equality, correct port attachment and legal containment. Test deterministic repetition, a second Arrange reaching a stable result, and small perturbations not causing unbounded growth. Include invalid inputs/work-budget exhaustion; preserve the input on failure. Set an interactive-time budget against a declared representative model size and hardware before timing, rather than inventing a universal threshold here.
**Third: verify the real workflow.** Parent performs Arrange, inspects routes and labels at normal reading zoom, Undo, Redo, save and fresh reopen on OA and SA models. Check that connections remain traceable and nesting still conveys the intended relationship; aggregate crossing counts alone do not establish readability. No such execution or acceptance is claimed by this research.
Recommended next decision: settle reset/preservation of bends, endpoint attachments and label anchors, then compare the native layered candidate and elkjs on the same compound, port-and-label fixtures. Route-only improvement is a useful fallback capability but should not silently redefine the user's Arrange request.
## Parent's current code findings: implication for the first experiment
Parent reports that the existing router already has deterministic bounded orthogonal search, obstacle exclusion, crossing/shared-run penalties and automatic label collision sampling; current Arrange uses a four-per-row root placement after topological/alias ordering. These are parent-provided inspection findings, not independent runtime verification here. They materially favor **reuse of existing routing plus improved node arrangement** as the first candidate, rather than reimplementing routing or immediately adopting another engine. Feed its final-route metrics back into a bounded choice among placement candidates; label sampling alone still cannot create missing corridor space.
Parent's proposed policy—preserve semantic ports, authored port anchors and endpoint attachment preferences; reset only visible effective bends/label overrides during explicit full Auto-layout; retain hidden/promoted metadata; leave automatic elbows derived—is a coherent candidate. Its key falsifier is visibility scope: a folded/proxy edge must not cause deletion of dormant metadata belonging to a hidden original endpoint/route. Define “visible effective” by exact original edge ID plus unsuspended geometry, not just membership in the rendered edge list. Test folded then expanded diagrams, ancestor-promoted endpoints, partially visible authored routes and a visible label whose anchor was inherited. If retained dormant metadata becomes effective on expansion, the restored manual shape is expected under this policy and should not be advertised as newly automatically arranged. Explicit full Auto-layout can reasonably reset visible label overrides because its stated purpose authorizes rearrangement, but ordinary redraw, drag and routing must not acquire that reset behavior.
Compare reuse against elkjs only after scoring this bounded candidate. A successful existing-router experiment removes much of the justification for another runtime; persistent compound/port-order failures would supply concrete reasons to reopen engine adoption. The newly observed untracked `harness/auto-layout-investigation-20260925.md` in the worktree is parent work; this research did not modify it or product source.
@@ -0,0 +1,51 @@
# #32 residual routes after terminal-join candidate J
Read-only diagnosis of run03 `command/output.log`, `.local/auto-layout-j-comparison-20260925.json`, the geometry-only crossed-bipartite PNG, and current `routing.rs` / `projection/port_layout.rs`. No edits, builds or native GUI execution. J is an experimental cost correction, not an accepted readability improvement for every scene.
## The remaining187 units are not coincident distinct ports
The four functional exchanges deliberately reuse four semantic ports:
| Flow | Source port | Target port |
| --- | --- | --- |
| 0 (`009`) | `010` | `014` |
| 1 (`00c`) | `013` | `011` |
| 2 (`00f`) | `010` | `011` |
| 3 (`012`) | `013` | `014` |
Projected source ports are `(264,106)` and `(264,286)`; target ports `(346,106)` and `(346,286)`. Each port is a single real semantic identity serving two edges. There are no authored port anchors in this fixture. The route endpoints and ports were unchanged by J. Splitting a common port into several displayed ports or changing relation port IDs would change the contract/semantics and is not a routing remedy.
Of187 pairwise shared units,72 are four legitimate common-port18-unit terminal stubs. The remaining115 are four avoidable interior overlaps:
- Flow0/Flow2: `y=106, x=282..328`, length46.
- Flow1/Flow2: `y=106, x=305..328`, length23.
- Flow1/Flow3: `y=286, x=282..305`, length23.
- Flow0/Flow1: `y=106, x=305..328`, length23. These routes have different endpoints, so this is not a common-port exemption.
These sum115. The two diagonals now have separate vertical channels (`x=328` and `x=305`); horizontal tails still merge different routes. The geometry PNG confirms that a user sees shared horizontal lines with branch contacts, not four independent readable connections. It is not native/glyph evidence.
`port_layout::layout` chooses automatic sides from peer centers, semantic fallback and clear exits; explicit anchors override the resulting side/offset. It sorts multiple automatic ports on a side by peer-axis coordinate and ID, then allocates distinct positions around fixed anchors. Here each node has only one relevant port, so improving distinct-port separation would not address this fixture. Moving a common automatic port could alter geometry but still leaves all its incident edges sharing the same physical endpoint. Fixed anchors must remain exact.
## J trades one objective against another
J improves layered diamond overlap82→36 (nonterminal0) and layered bipartite344→187 (nonterminal115). But the original unarranged bipartite regresses730→872 shared units (nonterminal658→800), while bends5→4 and length2076→2064. The current original routes use a320-unit top horizontal trunk and a160-unit second-diagonal tail; later straight edges overlap those trunks. This is consistent with a length/bend-biased objective, not evidence that J universally improves routing.
`crossing_cost` charges only0.12 per shared unit, capped80 per prior segment; a turn costs24. J now compares more complete turn costs, so it can rationally prefer a cheaper route with more overlap. The router evaluates edges in stable-ID order and does not jointly revise earlier paths. Terminal fairness alone cannot correct an objective that undervalues ambiguous shared strokes. Public/ordinary scenes must remain in the comparison; do not judge only Arrange-generated geometry.
## Next bounded experiment: penalty versus available lanes
Recommend a tiny factorial comparison with node positions, ports, anchors and edge order frozen: J; J+P; J+L; J+P+L. Keep the original unarranged bipartite as a named regression sentinel alongside layered diamond/bipartite and the existing corpus. This separates missing candidate geometry from cost preference; no placement change initially.
**P:** use one predeclared experimental overlap coefficient, e.g.3.0 instead of0.12, retaining the80 per-segment cap and proper-crossing24 initially. This is a falsifier, not a proposed final default. A12-unit dogleg around a straight shared span can cost24 additional length plus96 for four full-path turns. The cheap existing coefficient cannot compensate for that; even3.0 with the80 cap may still reject it. Record this failure explicitly rather than repeatedly tuning. A second experiment removing/changing the cap would require separate justification; the cap and segment subdivision make the objective unlike a simple global shared-length weight.
**L:** offer a bounded number of parallel candidate coordinates at `CLEARANCE=12` on either side of occupied horizontal/vertical segments, subject to current obstacle clearance and fixed terminal stubs. These are derived path candidates, never authored waypoints. Put them in fast-path candidate space and, if needed, the grid space consistently, with a deterministic global cap. The current obstacle-boundary/midpoint coordinate set does not systematically offer these close parallel lanes. More space between boxes alone cannot supply the missing candidate coordinate or change its cost preference.
A smaller staging of this comparison is to run P first and inspect actual chosen alternatives, then add L only if the recorded candidates lack the desired lane. Do not silently combine penalty, cap, edge ordering and node spacing changes. If P merely creates crossings/long exterior detours, that disproves it as a standalone improvement. If L offers legal lanes but they are never selected, that isolates the objective. The result may justify a different explicit priority or bounded shared-segment nudge, but not before this evidence.
**Alignment control:** an additional fixed24-unit inter-layer gap or stagger is lower priority. It changes the diagram and automatic peer positions, complicates attribution, and can lengthen shared trunks. Alignment may be useful for a particular placement heuristic, but it is not a direct explanation of identical horizontal tails between the same common ports. Port-placement changes are outside the identified dependency scope.
## Acceptance constraints for the experiment
Keep exact semantic graph, port identities, attachments, authored anchors and generated-versus-authored route distinction. Report raw overlap, legitimate terminal overlap, nonterminal overlap, proper crossings AND branch/bend contacts, labels, obstacles, length, turns, warnings and workload. Current proper-crossing zero excludes contacts at bends; trading coincident strokes for distinct, obvious crossings can improve traceability even if that one metric rises. Conversely, tiny offsets that appear merged at normal zoom are not success.
Use shared-port fan-out/fan-in and distinct-port controls, fixed-anchor controls, narrow corridor, authored-pin and opposite-direction routes. Compare original, reset-only and layered scenes, plus a fixed edge-ID permutation to expose priority sensitivity. Parent should inspect actual route tracing at normal zoom before adopting any weight/lanes policy. No quality acceptance or port-placement defect is asserted here.
@@ -0,0 +1,106 @@
# First automatic-layout experiment
## Decision
Retain the hierarchy/label-spacing prototype for further experiments; do not
adopt it as production Auto-layout. It improves several named fixtures beyond
resetting old bends, but regresses shared connector length in two fixtures.
Shorter routes and zero proper crossings do not establish readable connections.
The next experiment should isolate route selection at fixed node positions,
before adding more node spacing or replacing the existing routing engine.
## Method and receipt
Tested source `e7deea7039bcf31675cffbb462cfeb19d62a7e20`, based on released
`715036e132677dd2bc2fb37ed316d93dc9987aec`. No production file changed in that
commit. Windows x86_64-pc-windows-gnullvm, Rust 1.98.1, LLVM mingw, one Cargo job,
incremental compilation disabled; Linux excluded. Command:
```text
cargo run --locked --offline -p oa-core --example auto_layout_probe
```
The recorded runner completed at 2026-09-25T00:42:06Z, exit 0, unchanged inputs,
no recorded failure. stderr contains only compile/run progress. This means the
diagnostic process completed, not that layout quality passed. The JSONL has one
metadata record and nine fixture records, with full input/result Projects and
core route geometry. Its SHA256 is
`21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`.
[Evidence archive](run-01/probe-e7deea70.zip), 900995 bytes, SHA256
`c52f82d4782cd6a7f8cbe67498c8b2371e99204a65976aa8bcbbd0a86f835069`,
contains original receipts, source inventories, output, runners and 37 offline
geometry PNGs. [Manifest](run-01/manifest.json) binds every member and the
post-run executable identity. All archive members were byte-compared to the
local originals. Original absolute paths describe this machine; reproduce using
the source commit and command above, with a suitable Windows Rust toolchain.
## Observations
Values below compare existing Layout with the layered prototype. Reset-only
matches existing Layout except for the authored-detour fixture, where it already
reduces length to 240, bends to zero and area to 90816. Shared length is pairwise
segment overlap, not the union of occupied space; area uses recorded bounds.
| Fixture | Shared length | Label/node collisions | Route length | Bends | Area |
| --- | ---: | ---: | ---: | ---: | ---: |
| Four-node chain | 0 → 0 | 0 → 0 | 720 → 246 | 0 → 0 | 213312 → 150744 |
| Seven-node chain | 0 → 0 | 0 → 0 | 2560 → 492 | 8 → 0 | 523584 → 271920 |
| Diamond | 36 → 82 | 0 → 0 | 2200 → 688 | 8 → 4 | 300576 → 260832 |
| Crossed bipartite | 276 → 344 | 0 → 0 | 3284 → 688 | 12 → 4 | 300576 → 165360 |
| Nested cross-boundary | 0 → 0 | 1 → 0 | 1076 → 364 | 6 → 2 | 284096 → 366528 |
| Authored detour/label | 0 → 0 | 0 → 0 | 2348 → 187 | 6 → 0 | 628040 → 83820 |
| Fixed ports | 0 → 0 | 0 → 0 | 916 → 863 | 4 → 4 | 125976 → 116754 |
| Reversed children in two containers | 148 → 0 | 1 → 0 | 872 → 372 | 4 → 0 | 288512 → 272800 |
| Long ordinary labels | 36 → 36 | 2 → 0 | 1340 → 1436 | 4 → 4 | 200448 → 208800 |
Proper interior crossings, unrelated node overlaps, unrelated edge/node
penetrations, label/label collisions, unrelated label/stroke intersections and
route warnings are zero in the baseline, reset and candidate outputs. This is
not proof of crossing elimination: the crossing definition excludes bend and
T contacts, and overlapping strokes can make endpoint pairing ambiguous.
The parent inspected offline geometry for the reversed-container baseline and
candidate, crossed-bipartite candidate and long-label candidate. Reordering the
right container's children separates the two routes; the bipartite result has
a visually ambiguous shared central trunk. The long-label boxes occupy the
available corridors. These images render core boxes/lines, not actual label
glyphs or the desktop application, and therefore are not native UI acceptance.
Every candidate reports exact same-input determinism, idempotence and equality
to its first result for calls 2–10. Reported semantic, node identity/metadata and
nongeometry conservation hold. JSON and canonical single-source parse/format
round trips hold for all nine before/baseline/reset/candidate Projects. The
authored-detour route changes intentionally. These assertions do not separately
establish hidden-route or attachment lifecycle policy. Other-view conservation
is vacuous in these single-view fixtures.
Existing Layout's Session operation passes one-step Undo/Redo and history
checks. The pure candidate function has no integrated command/history evidence.
The [source review](probe-review.md) defines remaining metric and fixture gaps.
Folded/filtered topology, State/Allocation diagrams, cycles/undirected graphs,
large models, multifile sources, application/API admission and native editing
remain outside this run. Issue36's multiline State candidate is not in this base.
An [independent results audit](results-audit-01.md) checked receipt bindings,
complete Projects, all 37 image hashes and eight offline images. It independently
recomputed both shared-route regressions and confirmed the scoped conclusions.
## Implications
Resetting obsolete bends is useful but insufficient. Hierarchy ordering and
label clearance have distinct value, with measurable area/length tradeoffs.
Increasing a global gap cannot be assumed to fix shared-route ambiguity.
Inspect the existing router's candidate scoring and compare complete endpoint
join costs, overlap penalties and available lane candidates using the same
geometry. Preserve the full quality vector and endpoint/obstacle invariants;
reject a change that merely converts overlap into uncounted contacts.
The [routing inspection](routing-experiment-plan.md) identified a concrete
asymmetry: a locally selected route leg scores the source join but omits the
target-stub join until after choosing that leg. Test that small correction first,
at unchanged node positions, before the auditor's proposed alignment/spacing
alternatives. This is a falsifiable source-based hypothesis, not a conclusion
that it explains all shared routes. A separate committed candidate will preserve
this first control; no overlap weight or node placement should change in that
comparison.
@@ -0,0 +1,56 @@
# #32 first experiment — independent results audit
Source e7deea7039bcf31675cffbb462cfeb19d62a7e20, production baseline715036e132677dd2bc2fb37ed316d93dc9987aec. Command: `cargo run --locked --offline -p oa-core --example auto_layout_probe`; Windows x86_64-pc-windows-gnullvm/dev. Recorded exit0, failure=null, source inputs unchanged. Independently checked receipt-bound log hashes and equal before/after source inventories. No rerun, compiler, GUI or model helper executed.
**Conclusion: useful evidence for continued experimentation, not a production winner.** All nine finite fixtures completed; candidate conservation/repeat/roundtrip checks pass. Two shared-run regressions are real, while nested/reversed-container/long-label improvements are also supported. There are no predefined quality thresholds, so exit0 means the probe ran, not that layout quality passed.
## Verified results
Exactly one metadata row plus nine fixture rows. Every candidate is supported and valid as recorded, repeats exactly from identical input, equals its second-call result, and remains equal to its first result through calls2–10. Existing Layout likewise has passing repeat/history checks. Every before/after/reset/candidate canonical JSON and single-source roundtrip is recorded exact. Candidate semantic/node-identity/visibility/port-anchor/nongeometry booleans are true on all nine. I independently compared complete output Projects after restoring only diagrams, and checked target layout fields and route attachment fields against input: no difference. Most attachment lists are empty, so this is not broad attachment coverage. Other-view checks are vacuous for single-view fixtures.
The authored_detour_and_label candidate intentionally has authored_routes_exact=false because its three pins and label override are removed. That is the experimental reset policy, not an unexplained conservation failure. Reset-only already removes the detour; layered must earn its additional complexity elsewhere. Actual Undo/Redo was executed only for existing Command::Layout. Layered is a pure transformer with no command/UI integration or history evidence.
Values below compare **baseline Layout plus reset-only control → layered candidate**, not the original hand-placed input:
| Fixture | Shared length | Label/node pairs | Bends | Route length | Drawing area |
| --- | --- | --- | --- | --- | --- |
| flat_chain_4 | 0 → 0 | 0 → 0 | 0 → 0 | 720 → 246 | 213312 → 150744 |
| chain_7_row_wrap | 0 → 0 | 0 → 0 | 8 → 0 | 2560 → 492 | 523584 → 271920 |
| diamond | 36 → 82 | 0 → 0 | 8 → 4 | 2200 → 688 | 300576 → 260832 |
| crossed_bipartite | 276 → 344 | 0 → 0 | 12 → 4 | 3284 → 688 | 300576 → 165360 |
| nested_cross_boundary | 0 → 0 | 1 → 0 | 6 → 2 | 1076 → 364 | 284096 → 366528 |
| authored_detour_and_label | 0 → 0 | 0 → 0 | 0 → 0 | 240 → 187 | 90816 → 83820 |
| fixed_ports | 0 → 0 | 0 → 0 | 4 → 4 | 916 → 863 | 125976 → 116754 |
| two_containers_reversed_children | 148 → 0 | 1 → 0 | 4 → 0 | 872 → 372 | 288512 → 272800 |
| long_ordinary_labels | 36 → 36 | 2 → 0 | 4 → 4 | 1340 → 1436 | 200448 → 208800 |
All these control/candidate outputs report zero strict proper crossings, unrelated-node collisions, unrelated edge/node penetrations, label/label pairs, unrelated label/stroke pairs and routing warnings. Therefore this run provides **no discriminating evidence of proper-crossing reduction**. Zero warnings is not proof of unambiguous independent routes.
## Independently checked regressions and improvements
- **diamond:** shared length36→82. Control has two18-unit common terminal runs. Candidate retains those and adds one46-unit horizontal shared run for edge pair0009/000c. Nonterminal shared length0→46; this is not just a terminal-exemption artifact. Bends8→4 and length2200→688 improve, but they partially come with merged routing.
- **crossed_bipartite:** shared276→344, nonterminal204→272. Control has four18-unit common-tip runs plus204 horizontal. Candidate has those same72 terminal units, two additional46 horizontal overlaps, and a180-unit vertical overlap between distinct edge pairs0009/000c. Independent axis-interval sums match the emitted values exactly. A more compact drawing and fewer turns do not erase this distinguishability regression.
- **nested_cross_boundary:** reported label/node collision1→0 and route length1076→364; area284096→366528 increases about29%. The geometry PNG shows the parent widened to place its children horizontally. This is a real tradeoff, not universal improvement.
- **two_containers_reversed_children:** shared148→0, label/node1→0, bends4→0, length872→372 and area288512→272800. The hand-authored alternate child order exists independently; the candidate's straight separated connections support a meaningful ordering improvement over reset-only.
- **long_ordinary_labels:** label/node2→0, shared36 unchanged, but length1340→1436 and area200448→208800 grow. This is supported clearance-for-space tradeoff using approximate core rectangles, not native glyph evidence.
Viewed eight offline PNGs: baseline/candidate diamond, baseline/candidate crossed_bipartite, baseline/candidate nested_cross_boundary, candidate two_containers_reversed_children and candidate long_ordinary_labels. They corroborate route sharing and spacing changes. All37 image identities and their manifest binding to the original output log were checked. Images are schematic rectangles/polylines with fixed scale per fixture, not application renders or text measurements.
## Method limits versus actual failures
Proper-crossing definition excludes T contacts and bend intersections; shared length counts pairwise traversal multiplicity. I recomputed the two reported regressions independently from axis-aligned intervals, so those particular increases are actual geometry outcomes, not metric bugs. An unconditional dominance claim fails on those results, but the experiment has not predeclared a total preference ordering across compactness and sharing. Retain the whole metric vector.
Reset eligibility is post-baseline-Layout versus pre-layout in the candidate; equivalent for current unchanged-visibility fixtures only. No folded/filter/omitted-node/State/Allocation/undirected-cycle/dense scaling/UI admission/multi-file source lifecycle acceptance follows. The source work budget is partial and runtime complexity was not established here. No native GUI, universal label-ink correctness, candidate command Undo, or issue32 completion is claimed. Base715 lacks the separate36 measured State label follow-up.
## Next falsifiable experiment
Keep these nine frozen inputs and add one explicit orthogonal proper-crossing witness plus a non-incident overlap/touch counterexample to verify the evaluator distinguishes them. Then isolate diamond/bipartite routing interaction with a tiny predeclared set of node-placement alternatives (current top alignment, centered rank, deterministic stagger, conservative wider gap), keeping the router unchanged. Record actual routed metrics for every alternative; do not silently choose whichever plot looks best or optimize only bend count.
Hypothesis: a bounded alignment/spacing change can remove the candidate's excess nonterminal sharing without surrendering reversed-container and long-label gains. Falsifier: no alternative reaches control-or-better shared length while retaining no new obstacle/label collisions and predeclared reasonable area/length bounds. Use controls' reported geometry as a fixed comparator and preserve every alternative; if it fails, investigate router channel/parallel-edge handling rather than repeatedly widening all spacing or introducing a whole external engine. This next probe remains diagnostic; attachment/hidden-route sentinels and real command/history/native validation follow before production selection.
Evidence SHA256:
- 01-probe/command/result.json: `119179803e8c26b960ca4280e0429bb537a6f9ff5666267e49bfab989f48dc73`
- 01-probe/command/output.log: `21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`
- 01-probe/command/inputs-before.json: `2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe`
- 01-probe/command/inputs-after.json: `2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe`
- geometry/manifest.json: `022fa0f307f9fb92fccbbc139637c62f40d1dcc3a4ea555a35c6b08d82bdb3b5`
@@ -0,0 +1,92 @@
# Target-join scoring experiment
**Keep experimental.** Accounting for the target turn during route-leg selection
confirms the suspected source/target scoring asymmetry, but does not establish
uniform readability improvement. The original bipartite scene becomes more
overlapped. Do not integrate this branch as a completed Arrange fix.
Production routing/test source is `497c1ad8b39788148c5f03bc8542d6d8e28dbc01`.
Successor `08656b18bf8934cf264469cf68fc6dea97c15cbb` only resolves three strict
Clippy findings in the diagnostic observer. Probe runs at both commits emitted
the same 371192 bytes, SHA256
`f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
The [independent source review](terminal-join-source-review.md) and
[independent results audit](terminal-join-results-audit.md) retain the scoped
claims and limitations. The latter predates the completed contact audit below.
The [evidence archive](run-j/terminal-join-08656b18.zip) contains original runs
02–06, including the failed Clippy run, source inventories, full Projects and
geometry, comparison JSON, independent contact audit/script, runners and 37
offline geometry images. It is 3178939 bytes, SHA256
`bd2146237353af05b8667dc7bd728007143a2f1b24ad9f8728fdbc50ffb3368e`.
[Manifest](run-j/manifest.json) records every member; every archived byte was
compared with its original. Paths in original receipts identify the builder's
machine, not a dependency on a peer's filesystem.
## Checks and comparison
Windows Rust 1.98.1 gnullvm, locked/offline, one job, incremental disabled;
Linux excluded. All receipts close with unchanged inputs and no runner failure.
```text
cargo test --locked --offline -p oa-core --lib --test release_routing --test routing_geometry --test routing_labels --test state_diagrams --test group_movement
cargo run --locked --offline -p oa-core --example auto_layout_probe
cargo clippy --locked --offline -p oa-core --all-targets -- -D warnings
```
Tests: 185 passed, zero failed/ignored (132 library, 7 group movement, 13 release
routing, 18 routing geometry, 2 routing labels, 13 State). Three new private tests
exercise fast/grid terminal scoring in four orientations, absent continuation,
straight/reversal and zero-length legs. Existing authored-pin/attachment/history
checks pass. Initial Clippy rejected two manual-range expressions and one nested
if in the observer; after that observer-only cleanup, strict core/all-target
Clippy passes and the rerun output is byte-identical. No whole-workspace/native
acceptance is implied.
Across all 37 before/baseline/reset/layered/manual-witness variants, complete
Projects, projected nodes, projected ports and exact route endpoints are
unchanged versus the first experiment. This isolates routing/label placement;
it is stronger than merely reusing fixture input. All nine candidate invariants,
round trips, deterministic repeats and calls 2–10 remain exact. The candidate
still has no integrated command Undo/Redo evidence.
- Layered diamond: shared length 82→36, nonterminal 46→0; all other original
metrics unchanged. Remaining 36 units are common terminal stubs.
- Layered bipartite: shared length 344→187, nonterminal 272→115; routed drawing
area 165360→175960. Labels, bends, length and other recorded metrics unchanged.
Seven other layered metric vectors are unchanged.
- **Original bipartite regression:** sharing 730→872, nonterminal 658→800;
bends 5→4 and length 2076→2064. The scoring change can favor fewer bends over
distinguishable routes. This is not a monotonic quality improvement.
- Original diamond sharing 136→36; original two-container sharing 200→54;
existing Layout/reset-only two-container sharing 148→18. The independent
audit lists the complete changed vector; 30 of 37 variants are unchanged.
The separate Python contact audit uses orthogonal interval reasoning to
reconstruct BOTH old and new contacts. Primitive witnesses pass; all 37 new
contact/proper counts match Rust, and all 37 old proper counts match v1. Layered
diamond contacts decrease 3→2. Layered bipartite contacts increase 8→9: eight bend
contacts become six bend plus three T contacts. Proper crossings remain zero.
Thus decreased coincident length partly trades into branch contacts. Details,
edge IDs, coordinates and definitions are in the archive's
`support/auto-layout-contact-audit-result-20260925.json`; script is adjacent.
There is no inferred aggregate quality pass.
The parent viewed diamond/bipartite offline images: diamond branches separate,
but bipartite horizontal tails remain visually joined despite separate vertical
channels. These are schematics of core bounds, not native application or glyph
evidence. The [residual diagnosis](residual-routing.md) confirms four genuine
shared semantic ports; distinct-port placement is not the defect. Of 187 shared
units, 72 are bounded common-port stubs and 115 are avoidable interior overlap.
## Next discriminating comparison
Retain this J result as a frozen control. Test one predeclared overlap coefficient
3.0 instead of 0.12, with the existing per-segment cap 80, crossing cost 24,
node/port geometry and edge ordering unchanged. This P variant is an isolated
experiment, not a proposed default or a release-ready source change. Preserve
the original bipartite regression as a sentinel and the entire quality vector.
If stronger penalties cannot choose useful existing alternatives, inspect
bounded parallel lane candidates separately; do not silently combine scoring,
spacing, caps and ordering changes. A candidate that shifts overlap into hard-to-
follow contacts, label collisions or large detours has not solved the user task.
@@ -0,0 +1,112 @@
# Complete scoring/lane comparison
**Stop tuning these nine fixtures; retain the variants as experimental evidence.**
Bounded parallel lane candidates have some measurable value, but do not resolve
the compact bipartite ambiguity and introduce a routing-cost concern. The
stronger overlap coefficient is no longer present at the branch tip. No routing
or Arrange replacement has been accepted for production.
PL source `d0be9ff0674373fcf9623daf62bbf50dad02c4df` combines target-join J,
coefficient 3.0/cap 80 and bounded lanes. L source
`e8ec6dbb3160f62476a5557f14605f68959f65fe` restores coefficient 0.12, retaining
J and lanes. Each leg keeps every obstacle coordinate and adds at most 64
deterministic coordinates per axis at CLEARANCE offsets from settled other-edge
segments. Fast/grid searches receive the same augmented space. Endpoint geometry,
authored pins, attachments and model metadata are not edited by this operation.
The [source review](lanes-source-review.md) records attribution limits: retained
coordinates are bounded, but collection/sorting of prior segments is not charged
to the search budget. Extra axes can hit the existing grid-cell cap and can alter
grid scores through segment subdivision. This is not a proof of globally optimal
paths or constant preparation cost. No new engine/runtime dependency was added.
## Results
Every one of the 37 complete Projects, node sets, port sets and exact endpoints
matches its control in both comparisons. All nine candidate invariants,
roundtrips and repeated-call checks hold. Values below are raw pairwise shared
length for the crossed-bipartite fixture; complete vectors remain in the archive.
| Router | Original scene | Existing Layout/reset | Layered candidate |
| --- | ---: | ---: | ---: |
| Released router | 730 | 276 | 344 |
| J | 872 | 276 | 187 |
| J + stronger penalty (P) | 730 | 276 | 187 |
| J + stronger penalty + lanes (PL) | 724 | 72 | 176 |
| J + lanes, original penalty (L) | 724 | 276 | 176 |
PL's existing-Layout/reset result eliminates 204 nonterminal shared units but
adds one proper crossing, 24 route-length units and 19392 area units. Contacts
decrease 6→5; these tradeoffs stay explicit. L with the original coefficient
does not achieve that baseline improvement. Both lane variants leave 104
nonterminal units in the compact layered case, with nine point contacts. Its
drawing area returns from J's 175960 to 165360. Eight other layered metric
vectors are unchanged. The parent viewed the PL bipartite schematic: vertical
channels are separated, but horizontal tails still join at ambiguous branches.
Compared with J, L reduces original bipartite sharing 872→724 and original
two-container sharing 54→12 without changing the other original quality fields;
two-container baseline/reset sharing reduces 18→12. PL compared with P includes
a two-container original sharing regression 6→12 while reducing one bend, 12
length units and one contact. The [PL audit](penalty-lanes-audit.md) documents all
seven changed rows; no scalar is treated as a universal quality score. Labels,
obstacles and warnings remain separately checked. Core schematics and approximate
label boxes do not establish actual glyph layout or native route traceability.
## Verification and evidence
Same frozen Windows Rust1.98.1 gnullvm environment, one Cargo job, locked/offline,
incremental disabled. Linux excluded. All runs close with exit0, unchanged
inputs and no runner failure:
```text
# PL: five matched tests, including all three new lane tests
cargo test --locked --offline -p oa-core --lib lane
# L: 188 tests passed, zero failed/ignored
cargo test --locked --offline -p oa-core --lib --test release_routing --test routing_geometry --test routing_labels --test state_diagrams --test group_movement
# Both variants: complete nine-fixture diagnostic
cargo run --locked --offline -p oa-core --example auto_layout_probe
# L: strict core/all-target Clippy passed
cargo clippy --locked --offline -p oa-core --all-targets -- -D warnings
```
The full 188 check is for L, not PL: an existing private J test intentionally
asserts the original 0.12 cost. PL's filtered run executes three new lane tests
and two existing Scenario tests matched by `lane`; 130 other library tests are
filtered. Lane witnesses cover base-coordinate preservation, 64-extra bounds,
deduplication/order independence, relevance ranking, nonfinite rejection and
fast/grid selection of a feasible parallel path under the experimental cost.
**Cost signal:** routing_geometry's 18-test runtime is 16.43s under L versus
4.30s under J on the same machine/environment. This excludes compilation, but
is one suite observation per variant, not an isolated route benchmark or a
performance bound. It warrants profiling before adopting per-leg lane scans.
Whole cargo/probe elapsed times include compilation and are unsuitable for that
comparison.
The [independent final L/four-way audit](lanes-results-audit.md) confirms all 37
fixed bindings and the 188-test result, checks the recorded geometry/contact
evidence, and likewise recommends withholding L from production pending the
independent corpus and route-only timing.
[Evidence archive](run-lanes/lanes-e8ec6db.zip), 3518507 bytes, SHA256
`5512b4cbd99e3bf03eb975e25fb980f7b1a95a5cb19f3687fb3d6d83d1839e8f`,
contains original runs08–12, 74 offline images, complete comparisons, independent
axis-based contact audits, binary identities and runners. [Manifest](
run-lanes/manifest.json) binds every member, all byte-compared to originals.
PL output SHA256 `04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd`;
L output SHA256 `64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d`.
The earlier P result and original archive remain linked in [results-p.md](results-p.md).
## Decision and next evidence
Do not choose a global router policy from these nine scenes. Freeze a small
independent corpus before the next run: realistic authored nested/folded content,
mixed-direction shared/distinct-port fan-in/out with a fixed edge-ID permutation,
and a modest sparse diagram for isolated routing-time/budget observations. Compare
J and L with an explicit route-tracing rubric and full quality vector. Preserve
the original Scene/Arrange distinction and source/history lifecycle constraints.
This should decide whether the lane cost is justified or the simpler router
should be retained before broadening the Layout prototype. Fold/filter rules,
one-command Undo, API/source parity and real desktop acceptance remain required;
the separately pending State-label issue36 is not silently included here.
@@ -0,0 +1,50 @@
# Capped overlap-penalty experiment
**P alone does not solve the arranged bipartite overlap.** Source
`3d7adff923dee5bed54dfdccc119dbee0c7c2773` changes only the overlap coefficient
from 0.12 to 3.0 (plus an experiment comment), retaining the per-segment cap 80.
Node placement, ports, target-join J logic, edge order and crossing cost remain
unchanged. This is a transient diagnostic source variant, not a proposed default.
Windows command `cargo run --locked --offline -p oa-core --example
auto_layout_probe` completed exit 0 with unchanged inputs at
2026-09-25T01:04:57Z. Same frozen Rust1.98.1 gnullvm environment as J; Linux
excluded. Output SHA256
`13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7`.
J's 185 passing tests and strict Clippy are not claimed for P; this run executes
the diagnostic observer and its analytic primitives only.
[Original evidence archive](run-p/penalty-3d7adff.zip), 916568 bytes, SHA256
`6b819b01c8012aa72d423443f4dc04ae261f1ee9dc6907f0063c219ff173ad36`,
contains receipts, complete Projects/geometry, independent contact audit,
comparison, renderer output and runner. [Manifest](run-p/manifest.json) binds
original bytes and post-run probe executable; every member was checked against
its local original.
Complete Projects, nodes, ports and route endpoints are exact versus J in all
37 variants. All nine layered candidates retain the previous quality vector;
in particular bipartite sharing remains 187 (115 nonterminal), with nine contacts
and zero proper crossings. Two original-scene vectors change; the other 35 do
not:
| Original scene | Shared length J → P | Bends | Route length | Point contacts |
| --- | ---: | ---: | ---: | ---: |
| Crossed bipartite | 872 → 730 | 4 → 5 | 2064 → 2076 | 9 → 10 |
| Reversed children in two containers | 54 → 6 | 4 → 5 | 1512 → 1524 | 2 → 3 |
The bipartite result restores the first experiment's original-scene vector;
the extra bend/length tradeoff was predicted by the low overlap cost diagnosis.
Both contact increases remain visible rather than being counted as a clean
readability win. These results concern core geometry, not native route tracing.
The [independent P audit](penalty-results-audit.md) confirms these results and
all nine recorded conservation/roundtrip/repetition checks. Both additional
point contacts are T contacts; no proper crossing change is hidden by the table.
The next L comparison adds a bounded number of deterministic parallel lane
coordinates while preserving all existing obstacle coordinates and fixed
endpoints. Use the same augmented geometry for fast/grid search. P+L and J+L
will distinguish available alternatives from preference. The cap 80 may still
reject a four-turn detour whose extra length/turn cost exceeds it; retain that
outcome rather than retuning cap, ordering and spacing together. No weight or
lane policy is accepted for production by this diagnostic run.
@@ -0,0 +1,53 @@
# #32 next routing experiment: distinguish shared terminals from ambiguous trunks
Local source/receipt diagnosis only; no builds, formatters, GUI or product edits. Input: completed `e7deea70` probe `.local/auto-layout-checks-20260925/01-probe/command/output.log`; implementation read from `.local/auto-layout-20260925/crates/oa-core/src/routing.rs`. The probe uses **core estimated label bounds**, not renderer glyph measurement. No new candidate module is justified until the required private routing hook is agreed.
## Exact observed geometry
The layered diamond has 82 units of pairwise shared length: 36 classified as common terminal stubs, 46 nonterminal. Edges ending `009` and `00c` share the physical output `(264,106)`, its 18-unit stub to `(282,106)`, then an avoidable extra horizontal run to `(328,106)`. Edge `00c` then turns down to `(328,286)` and enters `(346,286)`. A candidate branching immediately at `(282,106)`, going to `(282,286)`, then right to the target would separate that extra 46-unit trunk while preserving the port and stub. This is a geometric proposal, not a verified collision-free final result; the same obstacle and label checks must evaluate it.
The layered crossed-bipartite case has 344 shared units: 72 common-terminal, 272 nonterminal. Its opposite diagonal routes both use `x=328, y=106..286`, an exact 180-unit coincident vertical run. Top and bottom horizontal portions add 92 nonterminal shared units. The source stubs are at `x=282`; target stubs at `x=328`. Proper crossings are reported as zero, but these coincident routes do not provide unambiguous independent traces. Do not treat the zero as a solved crossing problem.
## Source evidence: a local scoring asymmetry precedes penalty tuning
`crossing_cost` charges `min(shared_length * 0.12, 80)` per previously occupied segment, multiplied by segment count. A proper interior crossing costs24. `BEND_COST` is24. `RoutingSpace::new` uses obstacle boundary coordinates; fast-path candidates add the start/end midpoint, and grid coordinates add start/end. Neither systematically adds lanes offset from previously occupied trunks.
More importantly, `fast_path(start, end, space, previous, incoming)` includes the turn from the preceding source-side segment, but has no outgoing direction parameter. `route_edge` chooses this local path and only later appends the final target attachment point `b.point`; complete `path_cost` is then compared across endpoint choices, not across the discarded alternative paths for that same endpoint pair. With fixed semantic ports there may be no alternate endpoint choice to recover the discarded route. `grid_path` is only a fallback when `fast_path` returns None, not a better-cost search after a valid fast path.
For the diamond, horizontal-then-vertical has one internal bend and no incoming bend; its 46-unit shared portion costs5.52. Vertical-then-horizontal has one internal bend plus an incoming bend, costing24 extra locally. But appending the target segment adds the missing final bend to horizontal-then-vertical. Complete paths have equal bend counts; the local comparison prefers the shared route because it omitted one terminal join. The 180-unit bipartite overlap costs21.6, also below one turn. This explains a plausible bias, not proof that correcting it resolves every route.
## Minimal discriminating comparison (proposal to parent)
Freeze layered node positions, labels' text, attachments, port identities/anchors, edge order and work budgets. Compare a small fixed sequence, not an open parameter search:
1. **J: symmetric terminal-join cost.** Supply an optional outgoing point/direction to fast-path scoring. For the final segment to `b.stub`, use `b.point`; include `turn_cost(penultimate, end, outgoing)` both in actual candidate score and admissible pruning estimates where applicable. Intermediate authored pins have no predetermined outgoing direction; do not invent one. If grid routing supports this experiment too, target state selection must account for the terminal turn before returning the best result. Preserve baseline behavior for absent outgoing context. This isolates the suspected bias without stronger penalties or enlarged diagrams.
2. **JP: J plus stronger shared-run penalty.** One declared test coefficient, e.g.1.0 per unit with the existing80 cap, compared with0.12. Keep the proper crossing cost24 unchanged so the comparison exposes whether penalizing overlap merely substitutes crossings. Do not choose this variant solely by shared length. Preserve all hard endpoint constraints.
3. **JPL: JP plus bounded lane candidates.** For occupied horizontal/vertical trunks, offer parallel offsets of `CLEARANCE` on either side where applicable; validate obstacle clearance and fixed terminal stubs. Use a strict deterministic global cap on added coordinates/candidates and reuse existing work exhaustion handling. This tests whether absent geometric alternatives, rather than insufficient penalty, is the blocker. No persisted waypoint authoring and no unconstrained port movement.
4. **Spacing control.** Only if J/JP fail, compare the unchanged router with one fixed additional inter-layer gap (e.g.24 world units). This is a control, not the assumed remedy: larger gaps may lengthen shared trunks and enlarge diagrams while retaining identical topological ambiguity. Do not mix spacing and router changes in the first comparison.
The first J variant is the smallest informative next experiment. If it removes diamond's extra trunk while retaining invariants, stop and inspect results before implementing JP/JPL. A clean shared terminal fan-out need not eliminate its unavoidable initial18-unit stub. Conversely, sharing a node identity does not exempt arbitrary later overlap, and different physical ports on the same node must not be collapsed into one endpoint exemption.
## Required hook and ownership boundary
The candidate module can call public `route_diagram`, but cannot change private `crossing_cost`, `fast_path`, `grid_path` or candidate generation. Returning a changed Project with temporary authored waypoints would test a different policy and would violate the generated-elbows-remain-derived experiment. Copying the entire router into an example introduces unnecessary divergence.
Therefore propose a parent-owned isolated routing experiment hook, with no default production behavior change, or a separate disposable source variant controlled by the existing runner. Evaluator needs an optional routing provider returning `RoutedView` for a fixed Project, rather than only `candidate -> Project`. It must reuse that provider for every metric, capture, and repeat check and label the variant explicitly. Until parent approves that hook, no module/interface changes were made. The current original/reset/layered comparisons remain reproducible.
## Falsifiers and risks
Evaluate both raw and terminal-excluded shared length, proper crossings, T/bend contacts, route lengths/turns, unrelated-node/header penetration, label collisions, warnings and runtime/work counts. A positive overlap moved onto a bend is not a successful reduction in intersections. The crossed K2,2 fixture with fixed port ordering may require a genuine visible crossing or an outer detour; do not demand zero overlap AND zero crossings without a fixed-attachment feasible witness. Separate forced terminal contacts from independently traceable route interiors.
Keep diamond, crossed-bipartite, chain and long-label fixtures; add a fixed shared-output fan-out, two distinct ports on one node, opposite-direction connections, and a narrow obstacle corridor. Verify exact endpoint coordinates and metadata; preserve ordinary authored pins and preview/settled agreement if the routing change advances beyond this isolated experiment. Stable-ID order can privilege earlier routes, so rerun the same graph under a fixed edge-ID permutation and disclose sensitivity instead of relabeling edges to improve the score.
Labels are placed after paths settle; lane changes can worsen label collisions even when node positions stay fixed. Parent's eventual GUI inspection should trace each diagonal from its source label/port through the corridor to its intended target at normal zoom. No geometry metric alone establishes that user outcome. This note selects a falsifiable experiment, not an accepted product fix.
## Exact J patch plan, held for parent's separate candidate pin
No edits to `routing.rs` are authorized yet. After parent publishes the first experiment evidence, the narrowly proposed change is:
- Add `outgoing: Option<Position>` beside `incoming` in private `fast_path` and `grid_path` only. At `route_edge`'s loop over authored pins followed by `b.stub`, pass `Some(b.point)` only when `index == pins.len()`; pass `None` for every intermediate waypoint. The preceding settled path still supplies `incoming` exactly as now. No public API or metadata change.
- In `fast_path`, extend its shared `join(path)` closure with the terminal turn from `path[path.len()-2]` through `end` to `outgoing`, when two path points exist. Both `estimate(path)` and actual scoring already call `join`; change both consistently through that closure. Keep the two-bend lower-bound early exit: Manhattan distance plus two bend costs remains a lower bound for two-bend alternatives because terminal penalties are nonnegative. Keep final whole-path `path_cost` unchanged; local scoring does not persist a cost, so it does not double-charge the returned path.
- In `grid_path`, add the terminal turn **during relaxation when `next == last`**, using `turn_cost(a, b, outgoing)`. Include it in `costs[state]` and the queue priority before the target state can be popped. Do not merely add a penalty after returning the first reached target: that would fail to compare alternative arrival directions. The existing Manhattan heuristic remains admissible because the new terminal penalty is nonnegative. The initial incoming-turn logic remains unchanged.
- `start == end` has no locally selectable segment. Keep the degenerate result, and rely on whole-path scoring for the junction between preceding/following points. Do not fabricate a direction from an absent penultimate point. Waypoint positions/order remain exact; this patch does not claim globally optimal look-ahead across several hard-pin legs.
Focused tests before comparing full fixtures: (1) fast-path diamond geometry with one occupied horizontal trunk, fixed start/target stubs, asserting the equal-complete-bend alternative branches earlier; (2) directly exercise grid routing with two clear arrivals where adding the target join changes the preferred total, compare complete cost to an enumerated feasible alternative; (3) mirrored/rotated terminal geometry, including straight continuation and reversal costs; (4) outgoing=None preserves established intermediate-waypoint behavior; (5) full route with one/multiple authored pins retains exact pins and terminal attachments, plus start=end leg; (6) preview versus settled geometry remains consistent under the same baseline/budget. Use private unit tests for fast/grid so a passing public route cannot accidentally avoid the grid test. Then rerun the unchanged probe corpus and report the complete quality vector, especially any newly visible crossings. No expected overall improvement is asserted before execution.
@@ -0,0 +1 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -0,0 +1,217 @@
{
"source_commit": "e7deea7039bcf31675cffbb462cfeb19d62a7e20",
"baseline_commit": "715036e132677dd2bc2fb37ed316d93dc9987aec",
"scope": "Nine small SA FunctionalDataflow diagnostic fixtures; Windows core geometry, not native UI or production acceptance.",
"binary_after_completed_run": {
"path": "target/debug/examples/auto_layout_probe.exe",
"bytes": 24039424,
"sha256": "a95736170f58d25c60a16f2683b961aad8b31f97e4357c3e0d2f7e81d21176bd"
},
"members": {
"run/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"run/command/context.json": {
"bytes": 3488,
"sha256": "4dd4e602c2b33fd229a7241e1a4d6a2de399df197b5613af4b3126bfd357c476"
},
"run/command/inputs-after.json": {
"bytes": 1722092,
"sha256": "2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe"
},
"run/command/inputs-before.json": {
"bytes": 1722092,
"sha256": "2e56c60055651f59c58228fb3cdfbd4bfc6dea10236f333ae1824af9a928ecfe"
},
"run/command/output.log": {
"bytes": 331975,
"sha256": "21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1"
},
"run/command/result.json": {
"bytes": 4124,
"sha256": "119179803e8c26b960ca4280e0429bb537a6f9ff5666267e49bfab989f48dc73"
},
"run/command/stderr.log": {
"bytes": 279,
"sha256": "492e4346b5daf9d9eed2aa96c89c5104b9d8d7f830074b1346c9f5aaf053d662"
},
"run/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"run/orchestration.log": {
"bytes": 165,
"sha256": "e4bf56f792c8e8fc9288fc08ef5f0159941b8026e435a427722b59ccc4e34831"
},
"geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"geometry/crossed_bipartite-before.png": {
"bytes": 13413,
"sha256": "8622726dfdfc01e93fcd2d9d22c6d082e5a169b9dcd59f788e876954431214fd"
},
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13848,
"sha256": "de238d7e904a050b93cc63926f9b4b4723d4b98e6741971fc98f81d771a8a52e"
},
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"geometry/diamond-before.png": {
"bytes": 13255,
"sha256": "30d514155ec0e88a68e62089cd50b7747924a81095c957aa67b1bf5a70ac18f8"
},
"geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13581,
"sha256": "14dc1304822e74f8c7e0146a02af69ea39dc90d0d655a75b97383644c04b8900"
},
"geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"geometry/manifest.json": {
"bytes": 8099,
"sha256": "022fa0f307f9fb92fccbbc139637c62f40d1dcc3a4ea555a35c6b08d82bdb3b5"
},
"geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"geometry/two_containers_reversed_children-after.png": {
"bytes": 13950,
"sha256": "1536fa9da0fa89a64b12e7faf6d0dab1c3fa0177517e39fd1adaeaee3f2214fe"
},
"geometry/two_containers_reversed_children-before.png": {
"bytes": 14076,
"sha256": "2f3a2d55d30ff206d9daf9b8f84ba0e960332a02275289c66ab2e104da2e890e"
},
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14126,
"sha256": "2483bf404953ce9b3da38f2adca10c4e02e34638e2999acae7beecb5fe936a83"
},
"tooling/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"tooling/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
},
"tooling/auto-layout-format-precommit-20260925.json": {
"bytes": 364,
"sha256": "29c93825b415e04204d3fe23a85eef0798560bbb5a1a169689326602f65a9f35"
}
},
"archive": {
"name": "probe-e7deea70.zip",
"bytes": 900995,
"sha256": "c52f82d4782cd6a7f8cbe67498c8b2371e99204a65976aa8bcbbd0a86f835069"
}
}
@@ -0,0 +1 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -0,0 +1,398 @@
{
"scope": "Target-join candidate experiment, not production or native acceptance",
"runs": [
{
"run": "02-terminal-join-tests",
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
"exit_code": 0
},
{
"run": "03-terminal-join-probe",
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
"exit_code": 0
},
{
"run": "04-terminal-join-clippy",
"source_commit": "497c1ad8b39788148c5f03bc8542d6d8e28dbc01",
"exit_code": 101
},
{
"run": "05-terminal-join-clippy",
"source_commit": "08656b18bf8934cf264469cf68fc6dea97c15cbb",
"exit_code": 0
},
{
"run": "06-terminal-join-probe",
"source_commit": "08656b18bf8934cf264469cf68fc6dea97c15cbb",
"exit_code": 0
}
],
"observer_lint_cleanup_output_byte_identical": true,
"post_run_probe_binary": {
"bytes": 24156160,
"sha256": "3541618adc25d12ca136941e973f506cc11bc556840193023d4295c27be758a5"
},
"members": {
"02-terminal-join-tests/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"02-terminal-join-tests/command/context.json": {
"bytes": 3658,
"sha256": "6d8d90920415df092df40afb4031fdbd12d2bc87a0daebea692b9f9288804783"
},
"02-terminal-join-tests/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"02-terminal-join-tests/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"02-terminal-join-tests/command/output.log": {
"bytes": 18709,
"sha256": "f024aaba0fcb680d02d49b5afde398453cf5183a08b561ff96e4c9a42cf70a17"
},
"02-terminal-join-tests/command/result.json": {
"bytes": 4321,
"sha256": "4b56d6ac30cc87ba7c7757906a3d0258e056178528b56c77312bd9675ce579f3"
},
"02-terminal-join-tests/command/stderr.log": {
"bytes": 990,
"sha256": "73f8f63d3339affe4bf6b47408a2ed020aca62606dc14faa03be3f094550eccf"
},
"02-terminal-join-tests/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"02-terminal-join-tests/orchestration.log": {
"bytes": 179,
"sha256": "3c673d3e29089ce517cd6026946443f9ae8fcba2fccb384835fffe2e8e19b58d"
},
"03-terminal-join-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"03-terminal-join-probe/command/context.json": {
"bytes": 3502,
"sha256": "380e3e8fae97e1ee75417c1efc3ee64bdca1958aa61caa1766fba86a6c7e52d3"
},
"03-terminal-join-probe/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"03-terminal-join-probe/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"03-terminal-join-probe/command/output.log": {
"bytes": 371192,
"sha256": "f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f"
},
"03-terminal-join-probe/command/result.json": {
"bytes": 4166,
"sha256": "57a1f866b2cb67880decd26becf3ac2e7715e38bbd26d3089c47dd62294afa4f"
},
"03-terminal-join-probe/command/stderr.log": {
"bytes": 278,
"sha256": "686a3d705aa21b73652e7589b1fa44094bbbc05f3118b2886161e0f815c8a334"
},
"03-terminal-join-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"03-terminal-join-probe/orchestration.log": {
"bytes": 179,
"sha256": "bf0516c97a7f3003b29a549f463458f3dc5516b1f41af024e9cf7f6062b9280b"
},
"04-terminal-join-clippy/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"04-terminal-join-clippy/command/context.json": {
"bytes": 3521,
"sha256": "9f20479acb398ab0dc3c35708ddaef39e4457fcc22f910e13342163718d61fc0"
},
"04-terminal-join-clippy/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"04-terminal-join-clippy/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "bca5713f2201da1c52334e2bd941f76ea59efda5a3036bbb9b9ddd6ec5667606"
},
"04-terminal-join-clippy/command/output.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"04-terminal-join-clippy/command/result.json": {
"bytes": 4185,
"sha256": "fe9e21a9e203fa0ecfeed957041faa22180287a2ecd158f8a7e77b881ccffc1b"
},
"04-terminal-join-clippy/command/stderr.log": {
"bytes": 2728,
"sha256": "e375843af8e5bb8e921e78b7e7fca844787d6785710506f5e2c5c8b6788beb59"
},
"04-terminal-join-clippy/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"04-terminal-join-clippy/orchestration.log": {
"bytes": 182,
"sha256": "949915299dd53b9c59b5116da6f163973cc339d5ae3eb3b1a73151065f68bd6e"
},
"05-terminal-join-clippy/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"05-terminal-join-clippy/command/context.json": {
"bytes": 3521,
"sha256": "15bd08c0a37dc3e01a0d046b6cd1341aa11bfc858b8da92ad20512e8401e8815"
},
"05-terminal-join-clippy/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"05-terminal-join-clippy/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"05-terminal-join-clippy/command/output.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"05-terminal-join-clippy/command/result.json": {
"bytes": 4182,
"sha256": "6970eff6a4d9741e27acdb2ef2bfceefcd122c1590741edeb7a112f4f5c357d4"
},
"05-terminal-join-clippy/command/stderr.log": {
"bytes": 177,
"sha256": "5be2ed4d5b119d9b42e2b1e874e3c9e2d6b27cc0610c7d2300760f51a3dccdbe"
},
"05-terminal-join-clippy/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"05-terminal-join-clippy/orchestration.log": {
"bytes": 180,
"sha256": "dc27f63c6f1e1ea3c1e6ff6dac85cf49d5927f6784ee768c3c12b1e8ec62848f"
},
"06-terminal-join-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"06-terminal-join-probe/command/context.json": {
"bytes": 3502,
"sha256": "5500c31ead4f64132a628646a9863f587e59ef8281a74a70fcff9a038c283200"
},
"06-terminal-join-probe/command/inputs-after.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"06-terminal-join-probe/command/inputs-before.json": {
"bytes": 1725008,
"sha256": "721dfe221e70bc2fee3ffd53061d6ad154c01e843c0c8e325d5c70c756aa809c"
},
"06-terminal-join-probe/command/output.log": {
"bytes": 371192,
"sha256": "f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f"
},
"06-terminal-join-probe/command/result.json": {
"bytes": 4166,
"sha256": "bd3b20390a03ed7c637586119e12e0e55949303f9b17f6e018f231b1a9095833"
},
"06-terminal-join-probe/command/stderr.log": {
"bytes": 278,
"sha256": "8a49d76b8cf56f31f6877cb6baf9d9f82d5abfbc1bfcc2ae73b8d3ff209c482c"
},
"06-terminal-join-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"06-terminal-join-probe/orchestration.log": {
"bytes": 179,
"sha256": "e85db49cd4d73dbff0b45f92cfb96016f743db3e64878ceeee078515e7fe324d"
},
"geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"geometry/crossed_bipartite-before.png": {
"bytes": 13406,
"sha256": "aa3ba4f8ab67f6cd63d1c31fe309786e139db78ec6a36a0b00e8a854b590fe0c"
},
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13855,
"sha256": "e3cc0a326a2c8b577e40101c5f67ea9c3182bca6d3f0498cdc1f25a64df57b90"
},
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"geometry/manifest.json": {
"bytes": 8099,
"sha256": "0102449f730651a92233c4ae959e95e0a58036fe2b1c309224558c496241c741"
},
"geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"geometry/two_containers_reversed_children-after.png": {
"bytes": 13955,
"sha256": "1722ff21eaadd831e00b2176d61f8fa65b083d2fd5b633a196a3335d48ca125e"
},
"geometry/two_containers_reversed_children-before.png": {
"bytes": 14080,
"sha256": "78e765c579dd317e26177d0cd05cccc61519638e9198fdd0d344d9b54a95c1ba"
},
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14134,
"sha256": "ce6bc93dc38fe5b25552c8ebc5e778da175df53992e6a70ded8377fd99372587"
},
"support/auto-layout-j-comparison-20260925.json": {
"bytes": 76669,
"sha256": "3d5435686c2d23e97f08340693015ef66d1127726c9b5b5212678f43b3ad6b76"
},
"support/auto-layout-contact-audit-result-20260925.json": {
"bytes": 104481,
"sha256": "ec94203f42782d87c0459c251ab226567818e2715bc46a3e9ee0c25a6c15d620"
},
"support/auto-layout-contact-audit-20260925.py": {
"bytes": 9838,
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
},
"support/auto-layout-format-j-20260925.json": {
"bytes": 203,
"sha256": "5bd0e4b979aedf21bd38e4c41a1521dafffb78c3cccb61cd12dad56d4f4699e9"
},
"support/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"support/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
}
},
"archive": {
"name": "terminal-join-08656b18.zip",
"bytes": 3178939,
"sha256": "bd2146237353af05b8667dc7bd728007143a2f1b24ad9f8728fdbc50ffb3368e"
}
}
@@ -0,0 +1 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -0,0 +1,565 @@
{
"scope": "Finite PL/L experiments; no production/native/performance acceptance",
"runs": [
{
"name": "08-lane-tests",
"source_commit": "d0be9ff0674373fcf9623daf62bbf50dad02c4df",
"exit_code": 0
},
{
"name": "09-penalty-lanes-probe",
"source_commit": "d0be9ff0674373fcf9623daf62bbf50dad02c4df",
"exit_code": 0
},
{
"name": "10-lanes-core-tests",
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
"exit_code": 0
},
{
"name": "11-lanes-probe",
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
"exit_code": 0
},
{
"name": "12-lanes-clippy",
"source_commit": "e8ec6dbb3160f62476a5557f14605f68959f65fe",
"exit_code": 0
}
],
"post_run_l_probe_binary": {
"bytes": 24202240,
"sha256": "3c6a6fd09bc86e7e6b3ff1ace05540c103393d66bbb02c46bf0ebd6214fbabb1"
},
"members": {
"08-lane-tests/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"08-lane-tests/command/context.json": {
"bytes": 3478,
"sha256": "7f30e52a87c964d86e86229061be72372a9cfc1a3fad9a37c326370c38aec4ad"
},
"08-lane-tests/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"08-lane-tests/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"08-lane-tests/command/output.log": {
"bytes": 670,
"sha256": "1b3cc48bee9bb4d564f0479a692b7b20fa6df5da3b8dccfda5d1487b6b93f53e"
},
"08-lane-tests/command/result.json": {
"bytes": 4121,
"sha256": "9a48e66ce638944e885e708b3f361ce2d099352e154536a46fafa6bca49af12f"
},
"08-lane-tests/command/stderr.log": {
"bytes": 304,
"sha256": "c534ac6e8df5add7c08f663cd516b9a0da947a93127ebda6c378ede9bd42f575"
},
"08-lane-tests/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"08-lane-tests/orchestration.log": {
"bytes": 170,
"sha256": "bf1ebdbbdd1955bd7b874592340e3d79a48a145a9b39faec898aaa807133f81a"
},
"09-penalty-lanes-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"09-penalty-lanes-probe/command/context.json": {
"bytes": 3502,
"sha256": "4c95894559f60d51fda0e2af09b2ec66abf9dc687d623c1e67c9e042747d0084"
},
"09-penalty-lanes-probe/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"09-penalty-lanes-probe/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "2173ea00107237f320ab249a6fcde0ec616421aa09d6c274ef563e9974b47e6e"
},
"09-penalty-lanes-probe/command/output.log": {
"bytes": 371062,
"sha256": "04bb9ba4ab551a965cea130510cca6b96d9c1012911f191b14a7aa7efbf563dd"
},
"09-penalty-lanes-probe/command/result.json": {
"bytes": 4166,
"sha256": "538aa79bcedd4cf646c63d5309ec738be4676e2045715db1035a4f334a536117"
},
"09-penalty-lanes-probe/command/stderr.log": {
"bytes": 279,
"sha256": "126be48ed1535d641835bd72b6fc5aa05a9a2120dd2012daa3e30108eb1703e2"
},
"09-penalty-lanes-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"09-penalty-lanes-probe/orchestration.log": {
"bytes": 179,
"sha256": "4e398b4fed1ac76d6bd61cb18fe2c50cae2764f040d878006e464c5728428cd3"
},
"10-lanes-core-tests/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"10-lanes-core-tests/command/context.json": {
"bytes": 3655,
"sha256": "2ee756c13c33bccf0cb7c87492bb62be5d5203044a066af0af36389059b2181c"
},
"10-lanes-core-tests/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"10-lanes-core-tests/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"10-lanes-core-tests/command/output.log": {
"bytes": 19032,
"sha256": "bde8202db1c2f3f407a7dcbf6a1184830d0914e2bbba0e5f7cbd2c55d72d56b4"
},
"10-lanes-core-tests/command/result.json": {
"bytes": 4312,
"sha256": "828871867eb7ff0ccfd5953a694ae594ae145e89bf2eca831368297d1ea9b874"
},
"10-lanes-core-tests/command/stderr.log": {
"bytes": 990,
"sha256": "df86da47eb1884669f1d0ce14107713ea9afd9e3cbb68becf451a018a1bf7303"
},
"10-lanes-core-tests/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"10-lanes-core-tests/orchestration.log": {
"bytes": 176,
"sha256": "6a2f55638fd26b60333bcd61cc1faaa29baaf9041962cbc1cfacd762bfc933e5"
},
"11-lanes-probe/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"11-lanes-probe/command/context.json": {
"bytes": 3494,
"sha256": "d8ec80836b09c1859b7d482dbd2ebb0243495be3e022ce2cb5dcc5c47e9464bf"
},
"11-lanes-probe/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"11-lanes-probe/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"11-lanes-probe/command/output.log": {
"bytes": 371182,
"sha256": "64232f580600b7a874a6f4ceb128a6188fd5ff72655bc6b93d824ebed27ffb7d"
},
"11-lanes-probe/command/result.json": {
"bytes": 4142,
"sha256": "feee84c2fde115c22ea865033ff2d136da2aace1f1c8a7423c8add11358366a8"
},
"11-lanes-probe/command/stderr.log": {
"bytes": 278,
"sha256": "2e73f2722528e8f80b9e64f722643769e279d822835e9ea47e96cb07eaf51162"
},
"11-lanes-probe/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"11-lanes-probe/orchestration.log": {
"bytes": 171,
"sha256": "93c3867e1dc8b07314a7ac03db0d76b641eda2eaad1ad58a61914f1d6ec64794"
},
"12-lanes-clippy/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"12-lanes-clippy/command/context.json": {
"bytes": 3513,
"sha256": "eb644e36413cc55e61b7f6aa6162f7f17f21f67911123f951f1ed96c91b30430"
},
"12-lanes-clippy/command/inputs-after.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"12-lanes-clippy/command/inputs-before.json": {
"bytes": 1730052,
"sha256": "27af33c77ce384358dfbd8a6730d2eff7399575fb1cacbb2c338eaa441e5db91"
},
"12-lanes-clippy/command/output.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"12-lanes-clippy/command/result.json": {
"bytes": 4158,
"sha256": "ea20c2e64c26667f575b70b598a790aceb1804070c208e5f8f1dd7839e8b0a8f"
},
"12-lanes-clippy/command/stderr.log": {
"bytes": 177,
"sha256": "5e1eff044f676ea902db61f76e53375f034cc2cd33c8671a56d11dd4a2aa2936"
},
"12-lanes-clippy/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"12-lanes-clippy/orchestration.log": {
"bytes": 172,
"sha256": "44d905169275ce11c8f66e16ce232d750f6b2701e6fb085880e9ad013219d18b"
},
"pl-geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"pl-geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"pl-geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"pl-geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"pl-geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"pl-geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"pl-geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"pl-geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"pl-geometry/crossed_bipartite-after.png": {
"bytes": 13163,
"sha256": "bb809e93b44e802d05430903cf397618fb901efdb6c5ab272574064e20641af6"
},
"pl-geometry/crossed_bipartite-before.png": {
"bytes": 13399,
"sha256": "9b7af6a43ec655cdcb05da49b5fffea661d4f5c9a5ae70a0c74c6e7696b066d3"
},
"pl-geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13856,
"sha256": "c386b537f077f014e73e99831fdbb57e64ae9709a30afd2909dd50d7443c1899"
},
"pl-geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13368,
"sha256": "bdcf079498dc2dce5245e47eac8038d736cea7af6176ada13bf682671c70b4b4"
},
"pl-geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"pl-geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"pl-geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"pl-geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"pl-geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"pl-geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"pl-geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"pl-geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"pl-geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"pl-geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"pl-geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"pl-geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"pl-geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"pl-geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"pl-geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"pl-geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"pl-geometry/manifest.json": {
"bytes": 8099,
"sha256": "dc9c09882d841e6ba050caabf411de8dd0e868879fe8f0b7a1b44cece9ffde8b"
},
"pl-geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"pl-geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"pl-geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"pl-geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"pl-geometry/two_containers_reversed_children-after.png": {
"bytes": 13957,
"sha256": "b0911f8afb39313e6ce43661396d6553276d5db53c659937acf87252ed502c6e"
},
"pl-geometry/two_containers_reversed_children-before.png": {
"bytes": 14083,
"sha256": "2d42d34af4674bbf1739e85967d743e6fc78c117ef1e7645724c504b006ee881"
},
"pl-geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"pl-geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"pl-geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14136,
"sha256": "f690678d5697cbec20e64bf92a128a8fd3a1dffe3948fcbe75ad99a4f33de96d"
},
"support/auto-layout-pl-comparison-20260925.json": {
"bytes": 75815,
"sha256": "81f57e651a8840aaaeacc085df2eb90174b2e494182f6cd40ccd6d50e7bb531e"
},
"support/auto-layout-pl-contact-audit-20260925.json": {
"bytes": 103918,
"sha256": "60ce7e9735ceef50a92d29a0414aafe3d8fb6174dab99eff6397e2abc88e0afa"
},
"support/auto-layout-pl-binary-20260925.json": {
"bytes": 220,
"sha256": "00f0ceb0e92a156de2d870e32b1d57d88465e5acedd9c5f5e733f183a750c46e"
},
"l-geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"l-geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"l-geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"l-geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"l-geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"l-geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"l-geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"l-geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"l-geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"l-geometry/crossed_bipartite-before.png": {
"bytes": 13399,
"sha256": "9b7af6a43ec655cdcb05da49b5fffea661d4f5c9a5ae70a0c74c6e7696b066d3"
},
"l-geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13856,
"sha256": "c386b537f077f014e73e99831fdbb57e64ae9709a30afd2909dd50d7443c1899"
},
"l-geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"l-geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"l-geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"l-geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"l-geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"l-geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"l-geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"l-geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"l-geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"l-geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"l-geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"l-geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"l-geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"l-geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"l-geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"l-geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"l-geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"l-geometry/manifest.json": {
"bytes": 8099,
"sha256": "897b9d42b494bac1e5263a8bab42756c3038403948e6ac76028d86fd6e56ae20"
},
"l-geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"l-geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"l-geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"l-geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"l-geometry/two_containers_reversed_children-after.png": {
"bytes": 13957,
"sha256": "b0911f8afb39313e6ce43661396d6553276d5db53c659937acf87252ed502c6e"
},
"l-geometry/two_containers_reversed_children-before.png": {
"bytes": 14083,
"sha256": "2d42d34af4674bbf1739e85967d743e6fc78c117ef1e7645724c504b006ee881"
},
"l-geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"l-geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"l-geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14136,
"sha256": "f690678d5697cbec20e64bf92a128a8fd3a1dffe3948fcbe75ad99a4f33de96d"
},
"support/auto-layout-l-comparison-20260925.json": {
"bytes": 76659,
"sha256": "e1e23e6c2a50cd384457bb061d5b70a740f586f42767164fad9703ecbb4096a8"
},
"support/auto-layout-l-contact-audit-20260925.json": {
"bytes": 103893,
"sha256": "6f6cc674c27d3f43001fe1751ef3b09332caa9ddca396759f5525f811cbe1aaf"
},
"support/auto-layout-l-binary-20260925.json": {
"bytes": 220,
"sha256": "9c6d6e20c86237e5d1b917a981f2a5a8612d1c58b6e0706d4701e6c7cc59e06f"
},
"support/auto-layout-contact-audit-20260925.py": {
"bytes": 9838,
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
},
"support/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"support/auto-layout-format-j-20260925.json": {
"bytes": 203,
"sha256": "5bd0e4b979aedf21bd38e4c41a1521dafffb78c3cccb61cd12dad56d4f4699e9"
},
"support/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
}
},
"archive": {
"name": "lanes-e8ec6db.zip",
"bytes": 3518507,
"sha256": "5512b4cbd99e3bf03eb975e25fb980f7b1a95a5cb19f3687fb3d6d83d1839e8f"
}
}
@@ -0,0 +1 @@
* -text whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
@@ -0,0 +1,223 @@
{
"source_commit": "3d7adff923dee5bed54dfdccc119dbee0c7c2773",
"scope": "Transient P coefficient3.0/cap80 experiment, not production acceptance or claim that J tests pass with P.",
"post_run_probe_binary": {
"bytes": 24156160,
"sha256": "8f3ac5aa1fa01be6a8ab664e8ae269f6527b8ffb7e326c2926c8fae7c3d7e366"
},
"members": {
"run/command/changes.patch": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"run/command/context.json": {
"bytes": 3504,
"sha256": "6f6019b2be69e12e3270d8570e9e4950c93e42e8b3093a0e0324a30f7e5eb0ff"
},
"run/command/inputs-after.json": {
"bytes": 1727969,
"sha256": "607febcd0d74d11deaa07a44b8b9cf6c382fd65d55deadb2d8ac7e889797dcf1"
},
"run/command/inputs-before.json": {
"bytes": 1727969,
"sha256": "607febcd0d74d11deaa07a44b8b9cf6c382fd65d55deadb2d8ac7e889797dcf1"
},
"run/command/output.log": {
"bytes": 371606,
"sha256": "13111fe89e4e637d1af572a8a45b8bdd763e94b58a2ec5ec6ca83e40ffa209c7"
},
"run/command/result.json": {
"bytes": 4172,
"sha256": "6149122d05d77e02b463edb3dd359b06786bc4468c27d8cd625cbc1bc80c9894"
},
"run/command/stderr.log": {
"bytes": 279,
"sha256": "fe5d8d303700ef5b92bfaa95ac1f99a2214e1fc5f6c5ac8d83f6303aa258965b"
},
"run/environment.json": {
"bytes": 9463,
"sha256": "14e53dd6359601bdd9be3ad24c527fca96310d9eb4ffa91965f71841f8df2f82"
},
"run/orchestration.log": {
"bytes": 181,
"sha256": "db5af22d893966919b9342fd06b99e7e1c82c5c87593544b7762cc85f9a7e45a"
},
"geometry/authored_detour_and_label-after.png": {
"bytes": 12492,
"sha256": "44e30b94ef11b176155ab3df90fe5b52788c07442a42a355d3458fa904c147bd"
},
"geometry/authored_detour_and_label-before.png": {
"bytes": 12468,
"sha256": "097588fae4fd6253c25ab4b60be1ad685ead3a3012b206f382cec0be1341e700"
},
"geometry/authored_detour_and_label-experimental_candidate-metrics.png": {
"bytes": 13162,
"sha256": "82a07de168cda7dacdad2bd532dae408172466b2776acf8cfaabef6711c0539b"
},
"geometry/authored_detour_and_label-reset_only_control-metrics.png": {
"bytes": 12777,
"sha256": "e676edc49ec6ebb2fe29e976c36cba589f76330e7f9eb27b8835415a2ed5d225"
},
"geometry/chain_7_row_wrap-after.png": {
"bytes": 14271,
"sha256": "a020c1535e3d6e48cb5e6d7ae8403a256767c68ce26876fd773f3b626c61e365"
},
"geometry/chain_7_row_wrap-before.png": {
"bytes": 13771,
"sha256": "0b282cbd29eb3e29fa7d3bb9c3c9746caa14c77372b3191d78fa1a60743d0b11"
},
"geometry/chain_7_row_wrap-experimental_candidate-metrics.png": {
"bytes": 14396,
"sha256": "3ca042155d918083c5f4135ae059205b29b8ee5944819a6040a22eeb572f5f04"
},
"geometry/chain_7_row_wrap-reset_only_control-metrics.png": {
"bytes": 14549,
"sha256": "8828f289159deb0c2bedd130495197639775cd8edeb561f0de5501e2980d1e1d"
},
"geometry/crossed_bipartite-after.png": {
"bytes": 13144,
"sha256": "54a1b5e983bc9b6f619e67c13173d0ff5000e30f080aaf6c0a9064f59036f4b7"
},
"geometry/crossed_bipartite-before.png": {
"bytes": 13413,
"sha256": "8622726dfdfc01e93fcd2d9d22c6d082e5a169b9dcd59f788e876954431214fd"
},
"geometry/crossed_bipartite-experimental_candidate-metrics.png": {
"bytes": 13855,
"sha256": "e3cc0a326a2c8b577e40101c5f67ea9c3182bca6d3f0498cdc1f25a64df57b90"
},
"geometry/crossed_bipartite-reset_only_control-metrics.png": {
"bytes": 13349,
"sha256": "0b2a8c49368258b23c15a8e06bf9b881f0e53fed8b5fd7d6f216a09837634abc"
},
"geometry/diamond-after.png": {
"bytes": 12556,
"sha256": "6afcff1e5c10758e5eab3b803ec858d0af3da953be4af93df75257544a7252b2"
},
"geometry/diamond-before.png": {
"bytes": 13228,
"sha256": "38e341a1ed51d4b4a94513f34c3d48b05c72177dcc3792dc660cb780fd7f98c9"
},
"geometry/diamond-experimental_candidate-metrics.png": {
"bytes": 13555,
"sha256": "a61d178e2cd3fcff8fc4ed3c42e5ab71b042d26d776f59fe5eaadb3ef8481e5e"
},
"geometry/diamond-reset_only_control-metrics.png": {
"bytes": 12982,
"sha256": "48414d7a859c774f2cef51d0fc1512b1c9fe1540c540f96fac7f9531583d8731"
},
"geometry/fixed_ports-after.png": {
"bytes": 11889,
"sha256": "574cb0249c3bcc3140b9d61906332295a8462e32fbcd6b9526d8b05e202e38a0"
},
"geometry/fixed_ports-before.png": {
"bytes": 12013,
"sha256": "d07ef2105aa63f3aaacb19e9a7ca4960239b01f05f734baa6270657a465b4ab0"
},
"geometry/fixed_ports-experimental_candidate-metrics.png": {
"bytes": 12394,
"sha256": "d7fdcd7d4a1a014dd34243400dcd74a7596388fc5747853e5a6629535ca3083e"
},
"geometry/fixed_ports-reset_only_control-metrics.png": {
"bytes": 12231,
"sha256": "237e181db92baf49c24554ec4325137b014413603b62cb08dee63e6e68fa3e8d"
},
"geometry/flat_chain_4-after.png": {
"bytes": 12582,
"sha256": "7326cd482a61bea4cb787770449253a55f41e102794c8fc6a8500d9244c20cc7"
},
"geometry/flat_chain_4-before.png": {
"bytes": 12723,
"sha256": "b086e2b23d4b68cb43366725a26fbb39fdc2e87d18cd7109c9b3ec950ab665ba"
},
"geometry/flat_chain_4-experimental_candidate-metrics.png": {
"bytes": 13405,
"sha256": "3bb352dd5066a3b2cc5bb298c9f47a02416186421df4841b96c944e523d11104"
},
"geometry/flat_chain_4-reset_only_control-metrics.png": {
"bytes": 12918,
"sha256": "eba3eede6771a1ebfc7b773b48b599f5ca49613ad7444ab26acfea7d20dde515"
},
"geometry/long_ordinary_labels-after.png": {
"bytes": 12643,
"sha256": "f4f0c360e9ce44d631dd1d9f7c202954be943fdbede6288edbaddf9b890fcaec"
},
"geometry/long_ordinary_labels-before.png": {
"bytes": 12661,
"sha256": "3c17c1195337cda7cd4141a15428b66cac1475421600b6ecffc3db57dbfd9f94"
},
"geometry/long_ordinary_labels-experimental_candidate-metrics.png": {
"bytes": 13235,
"sha256": "d2931b576901fec68b23afd1a54d4c301eda4a75ba30184344749e0add277bc0"
},
"geometry/long_ordinary_labels-reset_only_control-metrics.png": {
"bytes": 12969,
"sha256": "68aacc7196a4995ff8a884a15ec91a31bd386bdd2d232fd2c27696a7f83cf791"
},
"geometry/manifest.json": {
"bytes": 8099,
"sha256": "c1b59384878e519efec99757efee571635f30d814247db2f183eebbf9c467a0f"
},
"geometry/nested_cross_boundary-after.png": {
"bytes": 13344,
"sha256": "51db6785ab89f5d92c61288604ae3c76aee467e291738b54466db5704c0eec8b"
},
"geometry/nested_cross_boundary-before.png": {
"bytes": 13547,
"sha256": "3b3963f5ef5a42106a006f1825ae5d85b722aa3bf163452ba986ef3369b57cc2"
},
"geometry/nested_cross_boundary-experimental_candidate-metrics.png": {
"bytes": 13535,
"sha256": "0ba365785753e748dc7c86c3f1eb5767f9ccb87c0ae0e18085e6a9d32b79f60d"
},
"geometry/nested_cross_boundary-reset_only_control-metrics.png": {
"bytes": 13549,
"sha256": "fbe21b57616459ecdbbd083dccd73bd120f5b7ad59a8ad80ea38cbbf9c3f49c1"
},
"geometry/two_containers_reversed_children-after.png": {
"bytes": 13955,
"sha256": "1722ff21eaadd831e00b2176d61f8fa65b083d2fd5b633a196a3335d48ca125e"
},
"geometry/two_containers_reversed_children-before.png": {
"bytes": 14092,
"sha256": "dcbc521b8e5efd6a201da8a724ed218a9f1331a8abb2eda299a5807828037cb9"
},
"geometry/two_containers_reversed_children-experimental_candidate-metrics.png": {
"bytes": 14500,
"sha256": "8a0744cf04d305a0431468395b3676604e03991e577f9f9d2f45e8497b1ef9ca"
},
"geometry/two_containers_reversed_children-manual_planar_order_witness-metrics.png": {
"bytes": 14531,
"sha256": "60623d358d9cb930c2c2c4995c9286c653e597c411b8879b77ac099fe9b0406b"
},
"geometry/two_containers_reversed_children-reset_only_control-metrics.png": {
"bytes": 14134,
"sha256": "ce6bc93dc38fe5b25552c8ebc5e778da175df53992e6a70ded8377fd99372587"
},
"support/auto-layout-p-comparison-20260925.json": {
"bytes": 77494,
"sha256": "9f228fbe78e1888c5d93e87dddd8d2effc01bab723929a87423c61e23f5cad66"
},
"support/auto-layout-p-contact-audit-20260925.json": {
"bytes": 104912,
"sha256": "6f4add5c81f6d16c45efabbefd9e36c9beb637b6823993f0d51adc3e20485ad9"
},
"support/auto-layout-contact-audit-20260925.py": {
"bytes": 9838,
"sha256": "398b9677d2ef2333514dd9c1ba5bc2f020c9927f395ed33bf11ac59b68139f46"
},
"support/run-auto-layout-check-20260925.py": {
"bytes": 2771,
"sha256": "d652c4df47f13aefc723bc54362d7b61308b8983c8d39ae7721c012519358ea2"
},
"support/run.py": {
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
}
},
"archive": {
"name": "penalty-3d7adff.zip",
"bytes": 916568,
"sha256": "6b819b01c8012aa72d423443f4dc04ae261f1ee9dc6907f0063c219ff173ad36"
}
}
@@ -0,0 +1,61 @@
# #32 Auto-layout source and evaluator map
Read-only inspection of `.local/auto-layout-20260925`, base715036e132677dd2bc2fb37ed316d93dc9987aec, on2026-09-25. Issue32 explicitly asks automatic creation/removal of bends, attention to connection intersections and labels. No source changes, compiler, GUI, model helper or Gitea writes were performed. No geometric outcomes below are claimed as measured results.
## Actual surfaces and shared execution
- `crates/oa-desktop/src/views.rs:443`: saved Architecture diagram toolbar **Auto-layout** sends `Message::Command(Command::Layout(id))`. `model_menu.rs:417`: background **Arrange elements** sends the same command. The generic chooser excludes Scenario, not State, but normal State navigation routes to its dedicated workspace. `behavior/state_menu.rs` returns early for the dedicated State menu, and `state_view.rs` has no equivalent Auto-layout button. State view creation still calls shared Layout (`behavior/state_edit.rs:361–410`); behavior creation batches Layout too (`behavior/creation.rs:477–504`). Distinguish exposed UI from callable core behavior.
- `crates/oa-core/src/model.rs:1431`: saved projection kinds are Overview, Decomposition, Allocation, Traceability, FunctionalDataflow, Capabilities, StateMachine and Scenario. `session.rs:947` accepts the first seven; Scenario explicitly refuses and requires its separate geometry operation. Process topology and Scenario lane/message arrangement are separate behavior canvases, not this generic command.
- Allocation **Arrange next drag / Alt+A** is a different manual translation workflow (`allocation_drag/arrange.rs`, `app/allocation_drag.rs`, `diagram/work_drag.rs`). Do not silently turn it into automatic graph layout or change its allocation/group/refusal/Undo contracts merely because its label contains Arrange.
- `app.rs:3559` applies pending property edits and remaps a changed diagram identity before executing Layout; preserve that admission/identity behavior (`tests.rs::placement_identity_edit_then_drag_and_diagram_identity_then_arrange`). `document.rs:322` prepares/validates a candidate, updates the source bundle with identity provenance, then commits one model/source history entry. Core Session execute at`session.rs:275` likewise records one changed candidate; Undo/Redo swap exact Projects and no-op candidates create no history.
- REST transactions at`crates/oa-server/src/routes.rs:1011–1041` accept serialized Command batches including Layout under expected-revision admission, with dry-run and atomic PreparedProject/store commit. Core behavior therefore cannot rely on desktop-only fonts/state. `docs/v2-interface.md` lists Layout convenience commands. CLI exposes check/lint/stabilize/rename-alias, not a direct layout verb. Text/source may store explicit node/route records; parsing/loading them must not implicitly auto-arrange.
## Current algorithm and why the issue is real
`session.rs::layout` measures a projection-parent forest, vertically stacks children below headers, and puts roots into rows of four. Roots use an exchange-aware topological-like ordering with alias/ID tie breaks and deterministic cycle fallback. Child order is placement-ID order. It changes node positions/sizes, computes per-node deltas and calls `projection::translated_routes`; it neither scores routed geometry/labels nor generates or removes stored waypoints.
`projection.rs:81` supplies actual visual parents: nearest placed semantic ancestor; Allocation derives performer grouping from allocation summaries; Traceability is flat; State filters the machine. Ports have owner placements, not independent node placements (`edge_endpoint_placements`). Measurement reserves minimum sizes, State action/internal rows and port footer (`session.rs:967–1006`). Folded descendants still belong to the authored forest; projected visibility and stored layout are distinct.
The router is **not unaware of crossings or labels**: `routing.rs:457` routes stable edge IDs with a bounded search and previous-edge costs; `crossing_cost:990` penalizes proper crossings and positive collinear overlap separately. All paths settle before automatic label placement; `label_geometry`/`label_collisions:1370–1552` consider node obstacles, earlier labels and all visible strokes. But routing remains greedy, has finite search budgets, and authored label placement bypasses avoidance. Auto-layout never feeds these costs back into node order/spacing. Existing pins constrain paths even after node arrangement, except folded/promoted routes temporarily suspend their custom geometry. Thus a node-only Layout plus pinned greedy routing cannot promise the joint improvement requested by32.
Base715 uses scalar-estimated label rectangles. The separate #36 measured State multiline layout is not present in this base; do not assume its geometry or acceptance has already integrated. Ordinary labels, association-end labels/stereotypes and State labels also differ in presentation. Parent should coordinate routing-file overlap with #36 before integration, not silently reimplement its measurement policy.
## Contracts requiring an intentional change
1. `harness/release-routing-contract.md:143–146` explicitly says Layout preserves pins, translating only equally moved endpoint owners, with Reset routing separate. `crates/oa-desktop/src/guide.rs:360` repeats **Auto-layout preserves pins**. These are directly incompatible with the user's requested automatic bend removal/generation and must be revised for the explicit whole-view operation, with Undo restoring prior authorship.
2. `crates/oa-core/tests/release_routing.rs::layout_preserves_authored_route_count_order_labels_and_undo` fixes route list count/order, two pins on each route and exact labels. Replace only the superseded Layout assertions with the new declared output contract plus stronger geometry checks; retain unrelated-diagram exactness and exact Undo. Do not remove all route-preservation tests.
3. `state_diagrams.rs::layout_reserves_internal_rows_and_state_routes_retain_hard_pins` combines two things: the **pre-Layout** router must traverse authored pins without mutation; the post-Layout assertions reserve State rows and source roundtrip. Preserve those valid assertions, and rename/split the test if Layout no longer retains pins. Its current body does not actually assert post-Layout pin preservation.
4. Decide explicitly whether generated bends remain derived route corners or become persisted editable waypoints. The user asks visible automatic routing improvement, not necessarily a new semantic field. `routing.rs` documents only authored pins in the model; blindly storing every solver corner would turn generated geometry into hard constraints and can cause second-run drift. Whichever representation is chosen needs first/repeat Arrange and manual-after-Arrange tests.
5. Define scope for invisible/suspended routes, authored label offsets and explicit attachments. User32 authorizes changing bends; it does not automatically authorize deleting manual semantic-port metadata, every hidden route, or authored label placement. A narrow baseline is reset/rebuild bends for eligible visible edges while retaining attachments, labels and unrelated/hidden records; measure whether that suffices. If an authored label constraint defeats label clearance, report it or make its intentional reset policy explicit instead of pretending the layout is collision-free.
## Invariants to retain
Complete elements/relations/traces/types/names/text/IDs/containment/allocations/occurrences remain exact; only the selected diagram's declared presentation fields may differ. Other diagrams, node identities, collapsed flags, view options, unplaced elements and manual port side/fraction metadata remain exact. Automatic port geometry may change with node geometry, but semantic port identity/contract and explicit anchors do not. Existing tests `port_anchors::separate_views_resize_layout_and_hidden_owners_keep_manual_metadata`, `workflows` nested-parent containment, and desktop port/identity tests are relevant sentinels.
Keep move-one-end pins-fixed and move-both-owners equal-delta translation in `projection::translated_routes`, normal drag/reflow/group previews, reconnect, folding suspension/resumption, Hide/show and Reset routing unchanged unless separately justified. Keep finite geometry and existing point-count/attachment/fraction validation (`validation.rs:650–720`), deterministic bounded failure/fallback, source/JSON roundtrips, dry-run nonmutation, rejected-operation no-history, and exact one-step Undo/Redo. A Layout improvement must not trigger new allocation/reconnect semantics.
## Independent fixtures and falsifiers to freeze before candidate comparison
Use hand-declared topology, IDs and geometry; record the old candidate's metrics once, then compare materially different candidates against the same evaluator. Do not use a candidate's own cost function as the acceptance oracle.
| Fixture | Independent observable requirement |
| --- | --- |
| Two connected OA activities / SA functions with redundant dogleg and one blocking third card | Explicit Arrange removes obsolete turns; unobstructed edge straightens, blocked edge gains necessary orthogonal turns; semantic endpoints exact, no nonincident-node penetration. Include authored source/target attachments. |
| Two containers, each with two children, reversed child-order connections | A planar hand-constructed witness has zero proper crossings; require zero on this bounded case, child containment and preserved port contract. Detect current ID-ordered child stacking weakness. |
| Four-node diamond plus return edge, self-loop, parallel and reverse-direction edges | No false cycle/deadlock; meaningful separation of parallel paths; self-loop remains visible; distinguish shared endpoint fans from mid-path overlap. Test swapped UUIDs and stable semantic aliases. |
| Five-plus roots and disconnected component | Exposes current every-four-roots wrap and ordering discontinuity. No overlapping cards, reasonable route/area bounds and deterministic repeated result. |
| OA/SA nested Allocation with ports, uniform subtree, folded ancestor and hidden route | Child interiors below reserved headers/footer, anchors on owner boundary, no fabricated ports, no semantic reassignment; hidden-route policy explicit; other view exact. |
| Traceability mixed OA/SA with duplicate placement sentinels elsewhere | Flat visual graph stays flat, valid edge identities and other diagram exact. |
| State machine with composite State, region, entry/exit boundary, internal/action rows and self-transition | State-specific legal boundary crossings, row reservations and no overwritten semantic state; shared Layout initialization remains valid even without a State Auto-layout button. |
| Long ordinary/association labels, adjacent parallel labels, and #36 B/W/U State cases once integrated | Independently measure label/node, label/label and unrelated stroke/label intersections using actual displayed geometry; native ink/readability check separate from advance-box arithmetic. |
| Dense/nonplanar or contradictory-anchor stress case | Finite time/work and explicit residual warnings/metrics; no claim all crossings can disappear. Preserve exact Undo and input on refusal. |
## Metrics and acceptance discipline
Report a vector, not a single opaque beauty score: (1) hard invalid geometry/illegal obstacle penetration and sibling overlap area; (2) label-node/label-label intersection area and other-edge strokes entering labels; (3) distinct proper edge-pair crossings; (4) positive-length collinear shared segments; (5) bend count after duplicate/collinear simplification, path length/stretch and total view bounds. Define endpoint/ancestor exemptions before running: parent-child containment is intentional, a shared semantic endpoint is not a crossing, owner leads and legal State boundary crossings are not nonincident obstacle violations. Deduplicate segment-pair crossing events at the same physical point; count edge pairs separately. Count near-parallel clearance as a separate readability observation, not zero-width intersection.
Use independent rectangle/segment math and full projected/routed outputs; export SVG and canvas must agree with those outputs. Include authored and derived labels, including association ends. A zero-crossing result obtained by coincident overlapping paths, gigantic detours, clipping labels or hiding edges fails the other metrics. Set fixture-specific route/area ceilings from a feasible manually declared witness rather than arbitrary post-hoc thresholds. Compare a second Arrange for idempotence, input-order permutation for determinism, pure camera changes for model invariance, then source Save/reopen and exact Undo/Redo.
Unavoidable cases: nonplanar graphs cannot all be planar with distinct nonoverlapping edges; fixed attachment orders, nested boundaries, coincident semantic endpoints and required self-loops can constrain clearance. Existing authored labels can intentionally occlude nodes. Report constrained residuals honestly and avoid turning ordinary automatic layout into deletion of semantic edges or impossible universal no-crossing guarantees.
The first useful milestone is a finite fixture/evaluator plus an explicit bend/label/hidden-route policy, then a prototype compared against current Layout. No need to expand into unrelated Process/Scenario geometry or redesign manual Arrange drag for this issue.
@@ -0,0 +1,39 @@
# J terminal-join actual-results independent audit
Result: the finite experiment supports the terminal-cost asymmetry diagnosis, with a real ordinary-scene overlap regression retained below. It does not establish universally improved routing, complete readability, or #32 acceptance. Static audit only: no compilation, probe rerun, GUI, source edit or publication by reviewer.
## Evidence and checks
Tested pin `497c1ad8b39788148c5f03bc8542d6d8e28dbc01`, compared against first probe `e7deea7039bcf31675cffbb462cfeb19d62a7e20`. Run03 command `cargo run --locked --offline -p oa-core --example auto_layout_probe`, Windows x86_64-pc-windows-gnullvm/dev: receipt exit0, failure null, inputs unchanged. Independently verified receipt log hashes. Test02 at the same pin also exit0/unchanged: six summaries132+7+13+18+2+13 =185 passed, zero failed/ignored.
Independently parsed both raw JSONL outputs, rather than relying only on comparison-helper booleans: all37 variant Projects, complete projected nodes/ports, and per-edge first/last coordinates match exactly. Thus changed area is routed/label bounds, not changed node placement. Independently recomputed every raw pairwise axis-aligned collinear interval total in both runs (74 variant observations); all agree with emitted totals.
All nine candidate rows report supported, identical repeated input, idempotence, passes2–10 equal first and previous, exact JSON/canonical-single-source roundtrips, no associated errors. Conservation remains true except the intentional authored-detour route reset (`authored_routes_exact=false`). Exact old/new Projects additionally confirm J changed none of these model records. Existing Command::Layout history/Undo/Redo checks pass in all nine rows; the layered candidate remains a pure Project transformation with no candidate-command history evidence. No native GUI evidence.
## Complete changed quality-vector rows
| Fixture / variant | Raw sharing old→J | Nonterminal sharing old→J | Other changed fields |
|---|---:|---:|---|
| diamond / before |136→36|100→0|none|
| diamond / layered candidate |82→36|46→0|none|
| crossed_bipartite / before |730→872|658→800|bends5→4; length2076→2064|
| crossed_bipartite / layered candidate |344→187|272→115|drawing area165360→175960|
| two_containers_reversed_children / before |200→54|200→54|none|
| two_containers_reversed_children / baseline |148→18|148→18|none|
| two_containers_reversed_children / reset control |148→18|148→18|none|
These are all changes in the comparison's pre-existing12-field quality vector; the remaining30 rows are unchanged. All baseline/reset rows outside the two-container case are unchanged. Seven of nine layered candidate vectors remain unchanged. Raw strict proper crossings remain zero throughout these comparisons; no demonstrated proper-crossing reduction follows.
The crossed-bipartite BEFORE regression is substantive, not a metric artifact: independent interval sums confirm142 additional shared units. Fewer bends and12 shorter length do not erase that readability tradeoff. Layered bipartite improves157 shared units but retains115 nonterminal units and grows routed drawing area10600 (~6.41%). Viewed its actual offline PNG: distinct vertical channels remain joined to shared horizontal routes. This is not an unambiguous-trace acceptance result. Diamond's remaining36 units are the separately classified common terminal stubs.
The new point-contact metric has no v1 field to compare directly: do not interpret its mere introduction as newly created contacts. Current layered diamond records2 contacts and bipartite9; the independent contact worker's retrospective audit is pending at this review. Counts classify contacts and do not alone establish readability. Approximate core label bounds, missing renderer/port-label measurements, finite fixture families, axis-only grid state, sequential edge ordering and no global hard-pin optimization remain limits.
## Binding and recommendation
- Old raw output SHA256 `21786ae5cb668f60e9252dc884668ee5e98289443d0b3723a9ea69bf21d47fd1`.
- J raw output SHA256 `f9ac7c1320b1cf026259bfcaf13a39e968ae317463712d8dc793375d9a4a541f`.
- Run03 result.json SHA256 `57a1f866b2cb67880decd26becf3ac2e7715e38bbd26d3089c47dd62294afa4f`.
- Comparison JSON SHA256 `3d5435686c2d23e97f08340693015ef66d1127726c9b5b5212678f43b3ad6b76`.
- Geometry manifest SHA256 `0102449f730651a92233c4ae959e95e0a58036fe2b1c309224558c496241c741`; all37 image byte lengths/SHA256 verified. These are offline geometry schematics, not native captures.
Recommendation: retain J as a successfully isolated scoring correction candidate, with explicit non-monotonic quality results. Before further penalty tuning, use the independently reconstructed contacts and the crossed-bipartite BEFORE regression as falsifiers for any stronger penalty/lane experiment. Keep exact Projects/nodes/ports/endpoints fixed and retain the entire vector, including labels and area. Do not advance directly to broad production quality acceptance based on the layered diamond improvement.
@@ -0,0 +1,25 @@
# Terminal-join experiment independent source review
Read-only review of the local candidate based on e7deea7039bcf31675cffbb462cfeb19d62a7e20; no compiler, probe, GUI or helper executed by reviewer. Reviewed routing.rs SHA256 43c2e983a132fd1c687706f5dc6b27867403aae2aa253cdc25195141d24759a5 and the accompanying v2 probe diff. Parent owns formatting, final source pin and execution receipts.
Recommendation: proceed with the bounded J experiment. No blocking defect found in the changed scoring or contact observer. This is source review, not test success or production acceptance.
- route_edge supplies the known target continuation only to the final leg, preserving intermediate hard-pin context. The final whole-path score remains unchanged; local selection does not persist or double-charge its score.
- fast_path applies the same incoming/outgoing join to both candidate estimates and actual costs. Its Manhattan + two-turn lower bound remains safe for genuine two-bend alternatives because joins/occupied-segment costs are nonnegative. Compacted zero/one-bend alternatives are already represented by the initial L candidates.
- grid_path charges the terminal turn before inserting target states into the queue. Manhattan remains an admissible and consistent lower bound for these nonnegative transition additions. Adding a charge after returning the first target would have been incorrect; this implementation avoids that trap.
- Zero-length spans retain the existing result and do not invent an arrival vector. turn_cost explicitly returns zero for a zero-length adjacent leg. Whole-route behavior around repeated pins remains covered by existing integration checks rather than a new optimization claim.
- New private tests exercise both fast and grid directly, four reflected/rotated diamond witnesses with independently stated complete cost310, absent outgoing context, straight continuation/reversal and degenerate spans. Full route pins, attachment metadata and preview/settled agreement still depend on the parent-planned existing suites; no passing result is inferred from their presence.
Important limits: grid states remain two axes, not four signed arrival directions, although turn_cost distinguishes reversals. This pre-existing state abstraction is not proof of globally optimal reversal-aware A*. The patch correctly incorporates target cost before arrival-state merging, but does not fix all possible intermediate state dominance issues. Fast routing is still preferred over grid whenever feasible; authored pins are solved leg by leg without global lookahead. Budget/obstacle fallback behavior is unchanged. These are not blockers to this finite asymmetry experiment, but must remain outside its claimed guarantee.
The probe contact metric is additive: closed point intersections deduplicate by edge pair and EPS-quantized coordinate, OR proper-crossing witnesses, distinguish endpoint/vertex/interior roles, and classify common terminals by both owner and physical coordinate without subtracting them. Positive collinear intervals remain in the separate shared-length metric; a noncollinear witness at their boundary can still count as a point contact. The analytic witnesses include proper, T, bend, endpoint, collinear-touch and overlap cases. These definitions are suitable for the finite orthogonal fixtures, not an exact general floating-point geometry theorem.
Execution interpretation: compare projected_nodes, projected_ports and exact emitted endpoints against the frozen first run before calling this a fixed-node experiment. The layered prototype itself reroutes while deriving spacing, so identical fixture input alone does not establish identical output placement. Preserve the full metric vector: replacing coincidence with point contacts/crossings or worsening labels must stay visible. No generic node/label layout or native traceability acceptance follows from this experiment.
## Formatting recheck and source identities
Original reviewed routing SHA256: `43c2e983a132fd1c687706f5dc6b27867403aae2aa253cdc25195141d24759a5` (measured by reviewer). Original evaluator SHA256: `b7e10e6d346bac93486b075229d8b5b4b74acba05b4bc5778cc60b89a7a6f4d3` (worker/parent-provided identity; reviewer inspected its actual diff).
Current formatted routing SHA256: `f482f6ef79ee0ef2c615a0ef7fff0d5ad0c56dd080efa8e374b7c29ab9961507`. Current formatted evaluator SHA256: `2cc8d3cb04f8a48bef02008e7b9a0d78aa254009ee85ef7d546df1d04f97ebca`. Both measured by reviewer. Reread full scoped `git diff --ignore-all-space` after formatting: scoring expressions, conditionals, witness coordinates/assertions and observer definitions agree with the pre-format reviewed output. Observed differences are wrapping/indentation and optional trailing commas in routing tests. There is no retained original-byte snapshot for a mechanical whitespace-only comparison; this is an independent source re-review, not a claimed byte-level proof.
Exact fixed-geometry comparators: per fixture and variant compare full `projected_nodes`, full `projected_ports`, and per-edge first/last coordinates in `routed_edges` with the frozen prior output. Compare endpoint owners to projected edge definitions, and preserve source/target attachment and semantic port identity/anchor metadata in the full Projects. New `route_endpoints` makes the current identity/coordinate association explicit; derive the prior coordinates from prior `routed_edges`, since v1 did not emit that new field. Inspect route/label changes only after those placement/attachment checks, and retain any mismatches as results rather than silently excluding fixtures.
@@ -0,0 +1,93 @@
# 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.
@@ -0,0 +1,36 @@
# 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.
@@ -0,0 +1,40 @@
'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')}));
@@ -0,0 +1,56 @@
# 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.
@@ -0,0 +1,32 @@
{
"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
@@ -0,0 +1,9 @@
# 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.
@@ -0,0 +1,7 @@
# 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.
@@ -0,0 +1,11 @@
# 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.
@@ -0,0 +1,33 @@
# 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.
@@ -0,0 +1,37 @@
"""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))
@@ -0,0 +1,239 @@
'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; });
}
@@ -0,0 +1,55 @@
# 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`.
@@ -0,0 +1,64 @@
# 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.
@@ -0,0 +1,52 @@
"""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'
@@ -0,0 +1,73 @@
# #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.
@@ -0,0 +1,45 @@
# 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.
@@ -0,0 +1,43 @@
# 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.
@@ -0,0 +1,47 @@
# 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.
@@ -0,0 +1,986 @@
{
"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"
}
]
}
@@ -0,0 +1,28 @@
# 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.
@@ -0,0 +1,11 @@
# 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.
@@ -0,0 +1,43 @@
# 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.
@@ -0,0 +1,57 @@
# 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.
@@ -0,0 +1,124 @@
# 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.
@@ -0,0 +1,51 @@
# 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.
@@ -0,0 +1 @@
* -text
@@ -0,0 +1,64 @@
# 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.
@@ -0,0 +1,37 @@
# 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.
@@ -0,0 +1,41 @@
# 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.
@@ -0,0 +1,21 @@
# 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.
@@ -0,0 +1,271 @@
{
"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
@@ -0,0 +1,55 @@
# 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.
@@ -0,0 +1,744 @@
{
"archive": "routing-independent-evidence.zip",
"bytes": 6545295,
"sha256": "fe88b4dccb41a639c7cca421d057c77652bfbdbeb908651e56b5a10274b0cdb6",
"member_byte_readback": true,
"members": [
{
"path": "binaries/j/build.json",
"bytes": 556,
"sha256": "88556a6d32ce1fd13c8831c88701e91eed5e195bce3daf440ddfaa9bf63d0973"
},
{
"path": "binaries/lanes/build.json",
"bytes": 570,
"sha256": "c20aa7deaf068d1923f0cadd6dec34dc3150a4a6d1859db4421a0091fce5487e"
},
{
"path": "binaries/released/build.json",
"bytes": 570,
"sha256": "e6d1676f9b89fcf711edd1cdaa149d578c15ccfcdfe893a8b6c7ab430fd947f5"
},
{
"path": "corpus/manifest.json",
"bytes": 10593,
"sha256": "a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717"
},
{
"path": "corpus/mixed_dispatch.json",
"bytes": 32787,
"sha256": "81d25af021cbad18af4262a220ba60372e51ca19083b7e80f2b19196baf05990"
},
{
"path": "corpus/mixed_dispatch_edge_ids_reversed.json",
"bytes": 32787,
"sha256": "25c95be6b6e7ad9ebcdc83aacc13fbbaa5a56651ba2843f8d1658c075ed789f8"
},
{
"path": "corpus/subsystems_40_sparse.json",
"bytes": 124043,
"sha256": "ad0ee7a0ab9c9f3c5f26a6d839f6627a82aa38858a3d5cc1ca87f5a8d795533e"
},
{
"path": "corpus/workshop_sa_folded.json",
"bytes": 102922,
"sha256": "ea5fd285d11795e5e543e4144349c32c92a5b328b8c5e2d1be8b75b70703dc97"
},
{
"path": "corpus/workshop_sa_original.json",
"bytes": 102923,
"sha256": "cc9b26390594513c11b3d85b768d244b2df8e7bed8cb76c4bdf0dc24db1d2ef6"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/context.json",
"bytes": 3599,
"sha256": "e780b950bbb8087003017e3649a507b738c3425ae09b64aa10301f0cb5520431"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/inputs-after.json",
"bytes": 1735049,
"sha256": "784d52a2766b11aba0a1c0c3f3a225b30e3e4ca0186c8b59f329f805992a5de4"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/inputs-before.json",
"bytes": 1735049,
"sha256": "784d52a2766b11aba0a1c0c3f3a225b30e3e4ca0186c8b59f329f805992a5de4"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/output.log",
"bytes": 100,
"sha256": "20f06b14f491c24c6951a4f5a75336919b666190a41f83295c733d488727ba08"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/result.json",
"bytes": 4244,
"sha256": "82d0cc88d8013ec8c05c9276c85300338eb19010473f2aabb35f8a2e7ced31e1"
},
{
"path": "routing-corpus-checks-20260925/01-generate/command/stderr.log",
"bytes": 366,
"sha256": "e439707594bbff491ca818d2cfd3ea66b3871943a036c131be8a684ade3292e4"
},
{
"path": "routing-corpus-checks-20260925/01-generate/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"path": "routing-corpus-checks-20260925/01-generate/orchestration.log",
"bytes": 171,
"sha256": "c5399c8626075ecac0187eef141e9c59dc022ce54c32445ea6c2aa0f593ad887"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/context.json",
"bytes": 3613,
"sha256": "8e383c2c18b49227c24b423f7908b442c3988d16516c61eafeeafdf45bb569d2"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/inputs-after.json",
"bytes": 1735049,
"sha256": "784d52a2766b11aba0a1c0c3f3a225b30e3e4ca0186c8b59f329f805992a5de4"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/inputs-before.json",
"bytes": 1735049,
"sha256": "784d52a2766b11aba0a1c0c3f3a225b30e3e4ca0186c8b59f329f805992a5de4"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/output.log",
"bytes": 107,
"sha256": "be957352ab5ae1aca47ae57d39765985f2417b91ee974583864a5ae104140019"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/result.json",
"bytes": 4272,
"sha256": "96601902508ef873612be164bc6adfbe7be799d1bcd63d68b27aeaa3dbed1f04"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/command/stderr.log",
"bytes": 257,
"sha256": "16f676779879f4832ef510d76fa6f63abf83c191eb393d388d885b15c6cdbbc5"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"path": "routing-corpus-checks-20260925/02-generate-repeat/orchestration.log",
"bytes": 178,
"sha256": "9cabeb98b46d4944fdf5867951bfbd9227ac32dc19ffb097dde76ad84cad7ab5"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/context.json",
"bytes": 3608,
"sha256": "bb9b5d39f9d36accbb9d10c5694ec5a333482d93fb060485adb59ab22f6fb9c2"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/inputs-after.json",
"bytes": 1735049,
"sha256": "a492a98cf40cb84d1fa9d46e5d11f0a98a2bf2ec03dd030013ebcdfc04d5521a"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/inputs-before.json",
"bytes": 1735049,
"sha256": "a492a98cf40cb84d1fa9d46e5d11f0a98a2bf2ec03dd030013ebcdfc04d5521a"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/output.log",
"bytes": 103,
"sha256": "58bd78b19f839933c31ca11f902daa5b38c0d14720003cca2dced8bf9249fc44"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/result.json",
"bytes": 4265,
"sha256": "965c9a3c82c8f2f2bd4b82158e2b15340b4f00fe427d19ca040ec54b3c92443c"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/command/stderr.log",
"bytes": 369,
"sha256": "1fe1b633ee58c0f1249354057013547561c8f4aa946d16b70553ab6102eb0b50"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"path": "routing-corpus-checks-20260925/03-generate-fixed/orchestration.log",
"bytes": 177,
"sha256": "22d5231c06be3af285ec1f4df4946292660dcfc70318c92fb23f4f9099e4e66a"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/context.json",
"bytes": 3622,
"sha256": "4b12917c2770834c59ed9be866e1132bc3056d6913eeae68ce95cdc494c47bdc"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/inputs-after.json",
"bytes": 1735049,
"sha256": "a492a98cf40cb84d1fa9d46e5d11f0a98a2bf2ec03dd030013ebcdfc04d5521a"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/inputs-before.json",
"bytes": 1735049,
"sha256": "a492a98cf40cb84d1fa9d46e5d11f0a98a2bf2ec03dd030013ebcdfc04d5521a"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/output.log",
"bytes": 110,
"sha256": "c3bec5cc117c1465de6872a49274c9cd622c117c5061b9b3a8a9141643e94a95"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/result.json",
"bytes": 4293,
"sha256": "bc1535e096dc19f27b405bb22cd6087ede32f69e1a171ab4b2a3a095ea2bbe5c"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/command/stderr.log",
"bytes": 260,
"sha256": "c061b9732c764caa80dc2bcba37f5b41eab0f45db45d9e3dd2eac4e20c7245b4"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"path": "routing-corpus-checks-20260925/04-generate-fixed-repeat/orchestration.log",
"bytes": 184,
"sha256": "497d19bd6fbaf3dfb4a6e4d54667dfc0275a9d484ca8658d9d9d91c0c9090ec1"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/context.json",
"bytes": 3567,
"sha256": "3940fa319e4587151d0db7f1c6dd1263ea2cd1a9305e3c487a0d8bd841f8a34f"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/inputs-after.json",
"bytes": 1738623,
"sha256": "03047439b559a298fc4ef0ca6cc3b113e4a53fa5df8e0456aeeab43d86f52441"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/inputs-before.json",
"bytes": 1738623,
"sha256": "03047439b559a298fc4ef0ca6cc3b113e4a53fa5df8e0456aeeab43d86f52441"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/result.json",
"bytes": 4219,
"sha256": "eee254721a983e49ffe929f1e0f70b06853565a23d261a326620c69529c947ce"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/command/stderr.log",
"bytes": 1905,
"sha256": "67da03bbab8006a70245e7b96ee5493793de0d5e5914f2c0bdc876ca2208d726"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"path": "routing-corpus-checks-20260925/05-build-lanes/orchestration.log",
"bytes": 176,
"sha256": "b35f03c05260c4c01e72a9c8234da36783676b741e887dba9497115e7c8ecb0e"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/context.json",
"bytes": 3573,
"sha256": "100c5a4d5eb776805b67f4a2f4a6304578cedd527f1b34ec74348535ee8c959c"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/inputs-after.json",
"bytes": 1738623,
"sha256": "1dbd1badc2494426719bd0e19eccf804f301d9f47bdb50ea7772a32d9c9b9008"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/inputs-before.json",
"bytes": 1738623,
"sha256": "1dbd1badc2494426719bd0e19eccf804f301d9f47bdb50ea7772a32d9c9b9008"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/result.json",
"bytes": 4234,
"sha256": "67fdba73a040aae0fbcc06fc2f1e27c6d1dc24d8c4dcb1f9d92dd58d7ea1aedb"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/command/stderr.log",
"bytes": 179,
"sha256": "b3986da5974723f61b3a8257786c9c0721e32f14534c35ae3cb92a119987723c"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"path": "routing-corpus-checks-20260925/06-build-lanes-fixed/orchestration.log",
"bytes": 180,
"sha256": "6da6086f8bbbaad90e3cefb8d9ac58ee7ef384601c2523381f0e6321c58bd2b3"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/context.json",
"bytes": 3563,
"sha256": "a3234c8d6b2e7258b1a3d39555fe58e459020bc0b3205440cdfd851d8c6b8cfe"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/inputs-after.json",
"bytes": 1738623,
"sha256": "447b0f3be97b1d4885e3c6c72308e75e78b78c8f3cd5d15711f3088896bec345"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/inputs-before.json",
"bytes": 1738623,
"sha256": "447b0f3be97b1d4885e3c6c72308e75e78b78c8f3cd5d15711f3088896bec345"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/result.json",
"bytes": 4204,
"sha256": "ce07dc5193bf2d5c875f19e576e821d303a414ab2f4ac31a9b0f281c24cb2c5a"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/command/stderr.log",
"bytes": 179,
"sha256": "e35e1e1566c879a49cb498a2b309a2c9193bbbd80cca790da79b6615f94ef187"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"path": "routing-corpus-checks-20260925/07-build-j/orchestration.log",
"bytes": 170,
"sha256": "8c4c6481f5aa21a6ef8ef53ed37420cde0da80f67e782c9ee9cb04ef5e909c3d"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/context.json",
"bytes": 3570,
"sha256": "60e081d0c2a3903e9cd1cf2bb961138c90824993857251dc6960709fa59d5261"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/inputs-after.json",
"bytes": 1738623,
"sha256": "16189a473862e3793be91a9d46063dff43cef609b19a8f87472d56eb2230b3fd"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/inputs-before.json",
"bytes": 1738623,
"sha256": "16189a473862e3793be91a9d46063dff43cef609b19a8f87472d56eb2230b3fd"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/result.json",
"bytes": 4225,
"sha256": "7745afe769aba3141cf258cd6c0b9344b5ceb84c37f9698f9433c5b4a8fb7659"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/command/stderr.log",
"bytes": 179,
"sha256": "8d6a94bea51603e4d6e7f296942356b2772b352ae9b406be8da946c755b69799"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"path": "routing-corpus-checks-20260925/08-build-released/orchestration.log",
"bytes": 177,
"sha256": "59b278df15f857851ad8d748a9f116ca7be21fadeb6fc6900049a205524921b0"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/context.json",
"bytes": 3519,
"sha256": "99ffd62ac4ff9900612bb0bc3e785a0f92d0ff63ffd8695f69110858f83e4a1c"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/inputs-after.json",
"bytes": 1738623,
"sha256": "16189a473862e3793be91a9d46063dff43cef609b19a8f87472d56eb2230b3fd"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/inputs-before.json",
"bytes": 1738623,
"sha256": "16189a473862e3793be91a9d46063dff43cef609b19a8f87472d56eb2230b3fd"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/result.json",
"bytes": 4176,
"sha256": "b836499659fb9229b4f44f97c7056e44ddb02f97fb736f69ca8ea264d6654a6a"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/command/stderr.log",
"bytes": 177,
"sha256": "c97eb40db6f4904093faae2961f0360dad2986b4be3a36ffc14ff6b83218477c"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"path": "routing-corpus-checks-20260925/09-observer-clippy/orchestration.log",
"bytes": 178,
"sha256": "1ca36161f9ff64871b19ff64cbbec01f889a4bfdc1344910bc08ca46b6bc286c"
},
{
"path": "routing-corpus-runs-20260925/01-released/receipt.json",
"bytes": 2682,
"sha256": "b9d83c9930c9cbbcdc069bb86bab557171eeebbe1ff1357fa98efe8e26642e3c"
},
{
"path": "routing-corpus-runs-20260925/01-released/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/01-released/stdout.jsonl",
"bytes": 11218,
"sha256": "ae4056cac47d41d6ab8f3585cb53c5a6d734dc60d3d7ddc3af84e97a7e41ecfc"
},
{
"path": "routing-corpus-runs-20260925/02-j/receipt.json",
"bytes": 2654,
"sha256": "7a1b3b837d512b9be3c8649644ac374a5732364e62090c18038e8b0ab994c683"
},
{
"path": "routing-corpus-runs-20260925/02-j/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/02-j/stdout.jsonl",
"bytes": 11219,
"sha256": "847db6381f23a9c4c4a2a01e0c2aa9adec65671ab99d136247e9f79385e5b8d9"
},
{
"path": "routing-corpus-runs-20260925/03-lanes/receipt.json",
"bytes": 2677,
"sha256": "750965ee4205793bfdcc66fd4080e3aa438df808c0844e62df0381b83f1c810f"
},
{
"path": "routing-corpus-runs-20260925/03-lanes/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/03-lanes/stdout.jsonl",
"bytes": 11221,
"sha256": "1f9e91d34c6ab828be8412ad4015e0bdef443e1f94f16b309355bb11ed2cb3f8"
},
{
"path": "routing-corpus-runs-20260925/04-lanes/receipt.json",
"bytes": 2678,
"sha256": "d5ad4ee28ba4b15b68afefc7957e995c13d3bf53bd6f3e0c4be1363039067763"
},
{
"path": "routing-corpus-runs-20260925/04-lanes/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/04-lanes/stdout.jsonl",
"bytes": 11221,
"sha256": "9600f47829425938d72f12666324e8fba45def4c6c5ee6073fb81c46383daf91"
},
{
"path": "routing-corpus-runs-20260925/05-j/receipt.json",
"bytes": 2656,
"sha256": "65ee12d5b456f0d097d085b1a6f226655f36977cc2b875056a9b5a35625a0f2f"
},
{
"path": "routing-corpus-runs-20260925/05-j/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/05-j/stdout.jsonl",
"bytes": 11220,
"sha256": "b3611d72e9c193aace8d0e05980b1860eb12d48ad26b7a8b57613fdfa07fbc20"
},
{
"path": "routing-corpus-runs-20260925/06-released/receipt.json",
"bytes": 2683,
"sha256": "9c6e8e9ef1012c6718744d2fe968e49c5ebc38ad190e910a68b81e558e7d67a6"
},
{
"path": "routing-corpus-runs-20260925/06-released/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/06-released/stdout.jsonl",
"bytes": 11220,
"sha256": "989af06061fbce0dcfd6bf164fec02362546a1702ae9a5cb144842861fdd3748"
},
{
"path": "routing-corpus-runs-20260925/analysis-receipts.json",
"bytes": 1816,
"sha256": "b5c091729f2496c764abec53ca9167580d308b8bdc78797bb902c54607634e54"
},
{
"path": "routing-corpus-runs-20260925/geometry-j/receipt.json",
"bytes": 2680,
"sha256": "81680314df505602fe2f05eb8f7e87296b92d66f1b30c0688a24a7a793a26152"
},
{
"path": "routing-corpus-runs-20260925/geometry-j/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/geometry-j/stdout.jsonl",
"bytes": 470513,
"sha256": "23874838cc63ac640c941939599af225762ffc3d1fa07ca0a954dc97a1d40db2"
},
{
"path": "routing-corpus-runs-20260925/geometry-lanes/receipt.json",
"bytes": 2701,
"sha256": "92dff19e9740315382c2a86d7270e5c4f553524d0a294f08791925fc6afca8de"
},
{
"path": "routing-corpus-runs-20260925/geometry-lanes/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/geometry-lanes/stdout.jsonl",
"bytes": 470437,
"sha256": "07ddac7f8515797a433aef9a0306850eadc457411666325a9f710c68473f9c68"
},
{
"path": "routing-corpus-runs-20260925/geometry-released/receipt.json",
"bytes": 2707,
"sha256": "d957c153fb80bcf2b95f0ba863f0f899bac29368e85d272bfcda4ea3bf97083e"
},
{
"path": "routing-corpus-runs-20260925/geometry-released/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "routing-corpus-runs-20260925/geometry-released/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"path": "routing-independent-corpus-20260925/manifest.json",
"bytes": 10593,
"sha256": "a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717"
},
{
"path": "routing-independent-corpus-20260925/mixed_dispatch.json",
"bytes": 32796,
"sha256": "9f0c3bb9e06028ca38746014e34638660760323044aad8e594ebd89b056edc7a"
},
{
"path": "routing-independent-corpus-20260925/mixed_dispatch_edge_ids_reversed.json",
"bytes": 32796,
"sha256": "2de27d96c21ed3a2d63a66eea44ce78744d66709956cd7db232f9178979f5789"
},
{
"path": "routing-independent-corpus-20260925/subsystems_40_sparse.json",
"bytes": 124043,
"sha256": "ad0ee7a0ab9c9f3c5f26a6d839f6627a82aa38858a3d5cc1ca87f5a8d795533e"
},
{
"path": "routing-independent-corpus-20260925/workshop_sa_folded.json",
"bytes": 102922,
"sha256": "ea5fd285d11795e5e543e4144349c32c92a5b328b8c5e2d1be8b75b70703dc97"
},
{
"path": "routing-independent-corpus-20260925/workshop_sa_original.json",
"bytes": 102923,
"sha256": "cc9b26390594513c11b3d85b768d244b2df8e7bed8cb76c4bdf0dc24db1d2ef6"
},
{
"path": "routing-independent-corpus-repeat-20260925/manifest.json",
"bytes": 10593,
"sha256": "a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717"
},
{
"path": "routing-independent-corpus-repeat-20260925/mixed_dispatch.json",
"bytes": 32796,
"sha256": "6c6708e2b5fa8224246dac428d42068f44436c05b28aba0483b69190504cadf1"
},
{
"path": "routing-independent-corpus-repeat-20260925/mixed_dispatch_edge_ids_reversed.json",
"bytes": 32796,
"sha256": "9378a170ac70992035536b50cb07b851dcfec28acc08ef92f2465edeaee93abe"
},
{
"path": "routing-independent-corpus-repeat-20260925/subsystems_40_sparse.json",
"bytes": 124043,
"sha256": "ad0ee7a0ab9c9f3c5f26a6d839f6627a82aa38858a3d5cc1ca87f5a8d795533e"
},
{
"path": "routing-independent-corpus-repeat-20260925/workshop_sa_folded.json",
"bytes": 102922,
"sha256": "ea5fd285d11795e5e543e4144349c32c92a5b328b8c5e2d1be8b75b70703dc97"
},
{
"path": "routing-independent-corpus-repeat-20260925/workshop_sa_original.json",
"bytes": 102923,
"sha256": "cc9b26390594513c11b3d85b768d244b2df8e7bed8cb76c4bdf0dc24db1d2ef6"
},
{
"path": "tools-and-analysis/analyze-routing-independent-20260925.py",
"bytes": 19925,
"sha256": "2816a8f56b888b28b611e0045b533f7bd2da1b06222430423b595463dc377903"
},
{
"path": "tools-and-analysis/analyze-routing-independent-v2-20260925.py",
"bytes": 22830,
"sha256": "a72895248175fc56667d7b86cb4120a840d931e74ab1149e9649bb82d179f1ae"
},
{
"path": "tools-and-analysis/audit-routing-corpus-contacts-20260925.py",
"bytes": 12483,
"sha256": "a6d95610a45faa3b4417df3c82059967d9729975fcf39dd1e9359ff1a20e0036"
},
{
"path": "tools-and-analysis/freeze-routing-corpus-20260925.py",
"bytes": 1452,
"sha256": "31317e3b66e7407d6ca68a6ee6087837b52e31341989dbd2401997220444d04b"
},
{
"path": "tools-and-analysis/preserve-routing-binaries-20260925.py",
"bytes": 1209,
"sha256": "969142ee22eee24d40a21e4ad854720a484c6e30325a92a9e6fc262001076b97"
},
{
"path": "tools-and-analysis/routing-independent-analysis-20260925.json",
"bytes": 7649923,
"sha256": "1634f06ef7c4e50ebcbec64423a9a8730c08c822bf0023572e62ca0281c96302"
},
{
"path": "tools-and-analysis/routing-independent-analysis-review-20260925.md",
"bytes": 6513,
"sha256": "dd07a61afb4717256565953f629d9e312b38dbca56fcc2c8b8db01f7230a45a4"
},
{
"path": "tools-and-analysis/routing-independent-analysis-v2-20260925-receipt.json",
"bytes": 2100,
"sha256": "16d036d4bf061ea35d297fc8d765ff6ff639825bc86fa065787d0cfc13427cd9"
},
{
"path": "tools-and-analysis/routing-independent-analysis-v2-20260925.json",
"bytes": 7687929,
"sha256": "88af679275d85dad44a10dfb1eb4da94b861125c5948062c450635bdeb9814fd"
},
{
"path": "tools-and-analysis/routing-independent-contact-review-20260925.md",
"bytes": 6764,
"sha256": "1e90af45a96adc6f3cda418c3c3a4362b2bb773c46df66fbd40508bf032a4e0e"
},
{
"path": "tools-and-analysis/routing-independent-contacts-20260925.json",
"bytes": 213737,
"sha256": "40b62731db7dc332b13021fa1f13bed176455feb2fb13d15998c761a4623b492"
},
{
"path": "tools-and-analysis/routing-independent-decision-review-20260925.md",
"bytes": 7539,
"sha256": "de8fc5cb4ec10bffa9780e80c272d9aa55eeedf4ea2cc7b81aeff45f77040e7c"
},
{
"path": "tools-and-analysis/run-routing-analysis-20260925.py",
"bytes": 1632,
"sha256": "0a5d44c80eb59841b5c9323c8e13370b30dc60b29e200de2fa8ab54a4ad6f338"
},
{
"path": "tools-and-analysis/run-routing-binaries-20260925.py",
"bytes": 2882,
"sha256": "903c1c21971e7c5d73875db7df578c442496a17f98e4dde7a437d5f116f54604"
},
{
"path": "tools-and-analysis/run-routing-corpus-check-20260925.py",
"bytes": 2793,
"sha256": "2726a397bd4ecb4dcfff6fc170a66ce2655229079f42335faa2a4bfe4a202f6d"
},
{
"path": "tools-and-analysis/run.py",
"bytes": 13814,
"sha256": "698ed7182726c77fa4a1c85fc6dd08187ed20689941f57e749e3f0bc845f3252"
},
{
"path": "tools-and-analysis/select-routing-variant-20260925.py",
"bytes": 930,
"sha256": "bee977f62516d2e610a4aa5addfc9f17af8c61103b5f69c61733b6e38a257ffa"
}
],
"excluded": "Executables reproducible from identified source/build commands; binary hashes preserved. New frozen inputs are also committed alongside this archive."
}
@@ -0,0 +1,36 @@
{
"source_commit": "f0eae74912061455453acd7ec17e2ddbe498ee2c",
"repeated_generation_byte_identical": true,
"files": [
{
"path": "manifest.json",
"bytes": 10593,
"sha256": "a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717"
},
{
"path": "mixed_dispatch.json",
"bytes": 32787,
"sha256": "81d25af021cbad18af4262a220ba60372e51ca19083b7e80f2b19196baf05990"
},
{
"path": "mixed_dispatch_edge_ids_reversed.json",
"bytes": 32787,
"sha256": "25c95be6b6e7ad9ebcdc83aacc13fbbaa5a56651ba2843f8d1658c075ed789f8"
},
{
"path": "subsystems_40_sparse.json",
"bytes": 124043,
"sha256": "ad0ee7a0ab9c9f3c5f26a6d839f6627a82aa38858a3d5cc1ca87f5a8d795533e"
},
{
"path": "workshop_sa_folded.json",
"bytes": 102922,
"sha256": "ea5fd285d11795e5e543e4144349c32c92a5b328b8c5e2d1be8b75b70703dc97"
},
{
"path": "workshop_sa_original.json",
"bytes": 102923,
"sha256": "cc9b26390594513c11b3d85b768d244b2df8e7bed8cb76c4bdf0dc24db1d2ef6"
}
]
}
@@ -0,0 +1,150 @@
# Independent routing corpus comparison
Issue [32](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/32).
**Decision: retain the released router for the separate Arrange-reset candidate.**
J and L remain experiments. L provides a substantial workshop overlap improvement,
but both candidates worsen a fixed ID-permutation case and neither has native
traceability acceptance. The timing screen passes on this corpus; the earlier
debug-suite cost concern is not reproduced here and is not thereby disproved.
No release, merge, issue closure, Linux build or native UI acceptance is claimed.
## Inputs and identified code
The [corpus plan](corpus-plan.md), [timing protocol](timing-protocol.md) and
[adoption rubric](adoption-rubric.md) preceded routing observations. Five complete
Projects are committed under [corpus](corpus/manifest.json): saved SA workshop,
its single collapsed-placement variant, ten-function mixed dispatch with shared
and distinct ports and an authored pin/label, fixed reversal of its fourteen
edge IDs, and a flat forty-function/fifty-five-exchange sparse workload.
All inputs validate; repeated corrected generation is byte-identical.
Generator source `a879341c` initially produced differing random suffixes in three
secondary-view placement aliases. Two original generations are retained in the
archive. `f0eae749` assigns fixed aliases; two new generations agree in all six
files, frozen at `f674e36c`. This was corrected before any routing observation.
The corpus manifest SHA256 is
`a58a6956e26b414e88fafd4fdb92e006050653a4149178f08df84128e3917717`.
Generation receipts and every input hash are retained.
| Variant | Router source | Common-harness build commit |
| --- | --- | --- |
| Released | `715036e132677dd2bc2fb37ed316d93dc9987aec` | `4fb3cdc721e6fb8d70141b9c8f59809c53e7f16c` |
| J: target-join scoring | `08656b18bf8934cf264469cf68fc6dea97c15cbb` | `3ea0e23b70edfcaf61b1e900afb00254c7e80f75` |
| L: J plus bounded lane coordinates | `e8ec6dbb3160f62476a5557f14605f68959f65fe` | `095ab3b35847654d40e7bab9815c2bceb77484d1` |
These are three router sources in one identical evaluator, not whole historic
product builds. Only `crates/oa-core/src/routing.rs` differs among their build
commits. Windows Rust 1.98.1 stable gnullvm/LLVM mingw, Cargo release profile,
one build job and incremental disabled. Original tool/configuration/source-tree
receipts identify the environment; executable hashes are in `binaries/*/build.json`
inside the evidence archive. Copies were preserved before another build replaced
the shared target outputs. No compiler or other evaluator ran during timings.
The first optimized attempt at `f674e36c` failed on the expanded geometry JSON
macro's recursion depth. `095ab3b3` extracts three serialization expressions
without changing their schema or routing. All three final builds passed;
the failed receipt remains in the archive. Strict core/all-target Clippy also
passes at `4fb3cdc7` (`09-observer-clippy`).
## Timing result
The fixed order was released→J→L→L→J→released. Each invocation loads/projects
outside the clock, then performs one retained warmup and seven measured routing
calls per case. All 210 measured calls completed without censorship or timeout;
each complete RoutedView and its endpoints equalled that invocation's warmup.
All nine timing/geometry receipts confirm unchanged input files and binaries.
The table gives the two invocation medians in milliseconds (first / second),
not a percentile or scaling guarantee.
| Case | Released | J | L |
| --- | --- | --- | --- |
| Workshop original | 0.541 / 0.663 | 0.716 / 0.441 | 0.579 / 0.577 |
| Workshop folded | 0.409 / 0.623 | 0.406 / 0.419 | 0.567 / 0.638 |
| Mixed dispatch | 0.215 / 0.213 | 0.285 / 0.259 | 0.422 / 0.407 |
| Mixed IDs reversed | 0.179 / 0.202 | 0.477 / 0.331 | 0.589 / 0.365 |
| Forty-function sparse | 2.260 / 2.704 | 2.225 / 2.306 | 2.966 / 3.210 |
Maximum observed measured call: 6.1959 ms. Every case passes the predeclared 100 ms
median/200 ms maximum screen and candidate ≤ 1.25×baseline + 1 ms rule in both rounds,
including L versus J. At sub-millisecond medians, the absolute1ms allowance and
visible run-to-run variation matter; do not market ratios as precise speedups.
This finite result does not dismiss the earlier 16.43 s versus 4.30 s debug geometry
suite observations, certify pathological dense scenes, or establish native
interaction latency. One existing folded route reports NoClearPath in every
variant: completing a fast call is not proof it found a clear route.
## Quality and invariants
| Case | Pairwise shared length: released / J / L | Proper crossings: released / J / L | Raw point contacts: released / J / L |
| --- | --- | --- | --- |
| Workshop original | 1042 / 1074 / 602 | 6 / 5 / 5 | 22 / 23 / 23 |
| Workshop folded | 1096 / 1096 / 1096 | 7 / 7 / 7 | 20 / 20 / 20 |
| Mixed dispatch | 132 / 132 / 132 | 0 / 0 / 0 | 5 / 5 / 5 |
| Mixed IDs reversed | 132 / 233.5999756 / 233.5999756 | 0 / 0 / 0 | 4 / 5 / 5 |
| Forty-function sparse | 496 / 372 / 372 | 24 / 25 / 25 | 32 / 31 / 31 |
L removes 440 shared units from the workshop, but estimated label/node collisions
increase 11→12 (J: 13), label/stroke intersections 5→6, route length 5744→5768 and
drawing area 786620→799376. J increases workshop sharing by 32 despite reducing
proper crossings by one. Sparse sharing improves 124 under both candidates while
adding a proper crossing; estimated label/node collisions remain 70. The ordinary
mixed case is unchanged. Under the fixed semantic edge-ID reversal, both
candidates add 101.5999756 shared units relative to released routing. Released
routing itself changes two of fourteen route polylines under permutation;
J/L change four. No favorable edge order was chosen after observation.
All variants preserve frozen Rust model values, projected nodes/ports/edges,
semantic-port tips and authored constraints, with exact canonical JSON/source
round trips. No new missing route, nonfinite coordinate, edge/node penetration,
node collision identity or per-edge warning was observed. The folded scene
retains four PromotedEndpoints warnings plus one NoClearPath on the fourth edge;
these are recorded, not masked or called successes. Four promoted owner pairs
are independently identified. Its saved Project has no authored routes, so this
does not prove suspension/restoration of nonempty folded pins.
The [independent contact review](contact-review.md) confirms all 60 metric
comparisons across fifteen geometry observations using separate axis arithmetic.
It retains raw proper/T/bend/endpoint contacts and shared intervals, including
common semantic terminals. Six mixed-case authored waypoint passages and 498
mixed/sparse semantic endpoint tips agree. This is geometry evidence, not glyph,
port-label, arrowhead, native trace-task or editing acceptance.
The initial analysis reported six full-Project mismatches: five numeric leaves
per mixed Project, repeated across the three routers. Direct Project JSON writes
short f32 decimals, whereas `json!(Project)` through serde_json::Value expands
them to f64 decimals. Only PortAnchor.offset and EdgeLabel.fraction differ,
at 0.3/0.4/0.6; all thirty leaves have identical binary32 bits. V2 compares exact
bits only at these explicitly typed schema paths; every other field remains
exact, with changed-field and adjacent-f32 negative checks. Original failed
analysis, script and receipts remain unchanged. The independently reviewed v2
analysis has zero failed checks; this is not an aggregate quality acceptance.
The new record supplements the prior [nine-fixture comparison](../auto-layout-20260925/results-lanes.md).
## Consequence and reproduction
The [decision review](decision-review.md) supports retaining released routing.
Stop this fixed comparison without further parameter tuning. Preserve J/L as
diagnostic alternatives; reopening adoption requires demonstrated named trace
task improvements without new ambiguity and appropriate native/runtime evidence.
The separate reset candidate addresses stale authored constraints with the
released router; connection-aware node arrangement, label quality and complete
Arrange acceptance remain open in issue 32.
From each identified build commit, using the recorded Windows toolchain:
```text
cargo build --release --locked --offline -p oa-core --example routing_cost_probe --example auto_layout_probe
target/release/examples/routing_cost_probe.exe harness/experiments/routing-independent-20260925/corpus/manifest.json
target/release/examples/auto_layout_probe.exe --route-corpus harness/experiments/routing-independent-20260925/corpus/manifest.json
```
Preserve each executable before switching source, and run the fixed interleaved
order without compilation. The protocol requires an external 90 s per-process
timeout because the internal 5 s censor is checked only after a call returns.
Portable analysis scripts, original outputs, build receipts, corrected and
failed analyses, source/configuration inventories and archive-member hashes are
in [evidence/manifest.json](evidence/manifest.json). Local absolute paths in raw
receipts identify this machine; peers must build from the linked commits and
use their own filesystem/toolchain setup. No local path is a shared artifact.
@@ -0,0 +1,15 @@
# Route-only timing protocol v1
Parent execution order fixed before any outputs: preserve optimized binaries for released router source715036e, target-join J08656b18, and lanes L e8ec6db in a common harness. Run released, J, L, then L, J, released, with one complete corpus invocation per slot. Do not overlap compilation or other evaluator processes with timed execution. External timeout is90 seconds per invocation; retain partial output and explicitly mark missing cases if it expires. One separate untimed geometry invocation per variant uses `auto_layout_probe --route-corpus MANIFEST`. No new layout or router parameter tuning is part of this comparison.
Prepared example: `crates/oa-core/examples/routing_cost_probe.rs`. No execution, compilation or formatting by its author. Parent owns optimized builds, corpus and runs.
Invoke a preserved **release/optimized** binary as `routing_cost_probe.exe <absolute-manifest.json>`. No rounds override: every case uses one timed warmup followed by seven timed measured calls. External manifest is `{ "schema": 1, "cases": [{ "name": "unique-name", "project_file": "relative/project.json", "diagram": "UUID", "description": "fixture purpose" }] }`. Project files are direct serde Project JSON, validated before routing; paths resolve within the manifest directory. Cases run in manifest order.
Projection, decoding, validation and Project clone happen once outside timing. Each Instant interval includes only `route_diagram` and result black_box; inputs pass through black_box before the clock. Result destruction, equality, endpoint checks, digest and printing are outside. Allocation performed by routing remains included. Each repeat's complete RoutedView is compared to warmup, outside the clock; any mismatch is emitted then exits unsuccessfully. Project equality is checked against its initial clone. Endpoint equality is relative to the warmup, not a substitute for the independent semantic endpoint/quality evaluator.
JSONL starts with protocol metadata, then one record per completed/censored case with all measured nanoseconds, warmup duration, median, observed maximum, counts/warnings, stable route-point digest and checks. FNV-1a64 is a diagnostic identity only; use external SHA256 receipts for corpus, source, executable and runtime binding. Full RoutedView equality covers more fields than the point digest. Metadata reports debug_assertions but does not prove compiler optimization settings; the build receipt must do so. No environment secrets/configuration are printed.
If warmup or any sample exceeds five seconds, finish that call, stop remaining repeats for that case and mark it censored. Median is null for censored/incomplete series; maximum is only of observed measured samples, possibly null. The threshold is not a timeout: a hung call still requires external process supervision. A warmup-only censored case has no repeated stability evidence. Process failure may leave only partial JSONL; never interpret missing cases as zero cost or successful completion.
Warmup is retained so cache-sensitive first-call behavior remains visible, but one warmup does not prove steady state. Retaining its RoutedView and the original Project adds constant memory pressure across variants; repeat comparisons may influence caches between calls. Measure the same frozen corpus with interleaved preserved binaries for base/J/L variants on one machine, using the same release toolchain/profile, runtime, machine load and manifest order; do not compare dev versus release or include compiler time. Repeat entire interleaved sessions when a difference is close to noise. Seven samples characterize this run, not a latency distribution or statistical guarantee. Pair timings with the parent's independently calculated geometry/quality vectors; faster routing alone is not acceptance.
@@ -0,0 +1,15 @@
# SCC conservation review — corrected run02
Source `2426d286483ab0445663221cd6010a3dadb89a97`; all14 cases supported. Independent Python-only raw-Project audit passes every reconstructed conservation/minimum/enclosure check and all38 receipt file hash/size bindings. No Rust, compiler, routing or GUI execution by reviewer. Original run01 script, failure record and review remain untouched.
All13 previously successful complete after-Projects **and complete metric objects are exactly equal** to run01. The newly supported `two_containers_reversed_children` has roots at(40,40) and(494,40), each stored308×446; children at(72,136),(72,300),(526,136),(526,300), each stored224×94. Final projected child heights132 leave valid32left/96top minimum padding; final root projection matches308×446.
Independently evaluated the new conditional restoration, rather than allowing arbitrary size changes: these are noncollapsed, unported, ordinary parents whose original projected minimum is308×446. With original authored size and the final child geometry, core's24-unit side/footer and64-unit header enclosure would produce280×416 at the exact same position. The supplied unchanged effective minimum therefore requires explicit stored restoration to308×446. Both parents satisfy this condition; no other previously passing Project changes. This closes the recorded single-case transfer defect, not a new SCC-policy improvement.
The complete expected Project retains semantic records, other diagrams, authored anchor arrays, identities/order and all nongeometry fields. Three eligible authored routes reset as in run01. Folded workshop's three latent descendants still independently follow their actual Allocation/semantic ancestor by(-680,0), with expanded sizes retained. No dormant/promoted authored-route translation or nonempty attachment coverage is present; do not infer it from the policy code.
All14 records report exact same-input output, exact calls2–10 against both first and previous, and exact JSON/single-source round trips. These are recorded Rust checks; repeated full Projects and source strings are not serialized for independent reconstruction. Exact intended node plans remain a source-gate assertion: the audit checks emitted final geometry against permitted full-model changes/minima/enclosures, not an independent SCC-packing implementation. No native quality or production acceptance follows.
Standalone checker `audit-scc-conservation-v2-20260925.py` SHA256 `66a1621ac04e73bf08637047ed623c7154c0219a3076be7246004e6bf134d4e2`; result `scc-conservation-audit-run02-20260925.json` SHA256 `2897af5f3d131e2633a8dc5c9385307516c7c4db227349b374d4d062423a425e`. Both are under `.local`.
Invocation: `python audit-scc-conservation-v2-20260925.py .local/scc-placement-20260925/run02 NEW_OUTPUT_JSON 2426d286483ab0445663221cd6010a3dadb89a97 .local/scc-placement-20260925/run01`. Expected source pin is mandatory and output refuses overwrite.
@@ -0,0 +1,17 @@
# Independent SCC Project-conservation review
Read-only arithmetic/JSON audit of `.local/scc-placement-20260925/run01`, source `4dd764fa6cfc6920350383e523ba5a597412ddf4`. No Rust/compiler/router/GUI rerun. Auditable standalone Python checker: `audit-scc-conservation-20260925.py` SHA256 `7ebe5726c49c0918a9fbd55f74e16cac484ccec9d13f9cada7a7b36672ff1035`. Final machine result `scc-conservation-audit-final-20260925.json` SHA256 `c9156b710323d940a712ca8973a2e823a422faf96ad9c509193968ecf2f7fdd9`.
All14 cases accounted for:13 supported; `two_containers_reversed_children` rejects with `Final Rust projection differs from intended node geometry`. Its absence of an after-Project prevents conservation/enclosure/repeat checks; this is unsupported coverage, not a passed case. Read back38 receipt bindings with exact byte sizes/hashes; no mismatch.
For every supported case, independently reconstructed the entire expected Project from before-Project, final emitted projected positions/effective dimensions, actual semantic endpoint-owner placements, preoperation visible non-promoted edge eligibility and original route records. Compared the complete structure exactly, rather than trusting conservation booleans. All pass. Only declared target placement geometry and three eligible authored route resets change: mixed, reversed mixed, and authored_detour_and_label. Route entry identities/order and remaining fields are retained. All semantic records, other diagrams and authored port-anchor arrays remain exact. Projected identity/visual-parent inventory and frozen minimum sizes remain valid. Existing effective dimensions retain authored stored sizes; compact collapsed dimensions retain expanded stored sizes.
The folded workshop supplies actual latent movement: Rescue response, Send advice and Assess incident each translate by(-680,0) with collapsed owner `75920e7a-4586-58b7-9eb2-7e0a3d8a1825`. This was independently recovered through source Allocation/role/per-leaf performer and semantic ancestry relationships, not inferred merely from equal observed deltas. All hidden sizes/metadata remain exact. Supported final child enclosures satisfy left/right/bottom32 and non-State top96. This does not test State-specific header geometry.
All13 supported records report same-input exactness, nine repeat comparisons for calls2–10 equal both previous and first, and exact JSON/single-source round trips without errors. Those flags originate in Rust: repeated full Projects and source strings are not serialized, so this audit does not claim independent reexecution of them. Exact intended PlacementPlan nodes are also absent; the source final-reprojection gate checks that relation. This audit independently validates allowed full-Project changes, minima and enclosures using the emitted final projection, not a separate derivation of the SCC packing output.
No surviving dormant/promoted authored routes occur in supported fixtures; retained-route equal-delta translation and nonempty authored attachment cases therefore remain unexercised here. They must not be claimed from the checker implementing that policy. No quality, native workflow, full-router success or production adoption follows from conservation.
Audit development truth: initial local JSON reported one folded mismatch because the Python enum reader omitted unit-string bodies such as `{"Sa":"Function"}`. Inspecting the raw source established that checker defect; it was corrected before final assessment. Original JSON remains preserved, along with the intermediate v2 result. Final rerun additionally checks projected minima and visual-parent identity; all checks pass. No model or research source was edited.
Reproduce with Python only: `python audit-scc-conservation-20260925.py RUN_DIRECTORY NEW_OUTPUT_JSON`. Output creation refuses overwrite. Input strings are explicitly UTF-8; the checker invokes no application binaries.
@@ -0,0 +1,43 @@
# SCC placement: independent pre-result criteria
2026-09-25. Proposed experiment criteria for issue32, not production acceptance. Read `connection-corridor-sharing-diagnosis-20260925.md` and the previous placement/clearance findings. Research HEAD at inspection is `ae9dad54b749201c988fc398dbbc580db43e746f`. No new candidate source was reviewed for this record; author was asked to signal readiness. No compiler, router, engine or GUI execution.
**Proceed with one bounded SCC-condensation placement experiment, but make the planning graph and its relationship to authored containment explicit.** The observed native prototype interleaves four10-node sparse SCCs across16 ranks; moving to component-aware ordering directly tests that diagnosis. A compact perimeter is a falsifiable packing choice, not a consequence of SCC membership: strongly connected graphs are not generally simple cycles and need not have a crossing-free perimeter drawing.
## Material design risks to settle before results
1. **Do not confuse a hierarchy quotient with the actual connection graph.** At a containment level, mapping endpoints onto child/subtree representatives can introduce a proxy cycle even when underlying leaf connections are acyclic. Conversely, running independent leaf SCCs inside each parent can miss a real cycle crossing two containers. Preserve authored parent relationships; never reparent semantic nodes merely to make an SCC into a box. Record the exact vertices and mapped edges used for each SCC calculation, including planning parent and representative mapping. Call quotient components local placement blocks when appropriate; do not claim they prove global semantic SCC coherence.
2. **Perimeter order is a separate decision.** A component with ten vertices has many possible circular orders. An alias order or DFS order can recreate long backward edges, crossings and shared outer corridors, even after rank stretching disappears. Freeze a deterministic order before outputs, keep the edge-ID permutation, and disclose which connection information determines internal order. Do not rotate/reverse individual cases after seeing results. Singleton, two-node component and self-loop handling must be explicit; no duplicate placement at a repeated perimeter corner.
3. **Undirected means no authored direction.** An undirected relation can inform adjacency/proximity, but must not silently acquire a semantic arrow to satisfy the SCC algorithm. If treated as two directed adjacency arcs, state that it intentionally merges connected regions into placement blocks and may hide the directed condensation structure. If excluded from directed rank/SCC formation, keep it in geometry/quality evaluation and describe that weaker influence. A deterministic geometric orientation is another possible policy, but must remain a placement-only preference. Do not repeat the previous workshop omission without reporting unsupported cases.
4. **Local label gaps still have to cover actual routes.** A gap computed for one rank boundary does not guarantee space for long edges, perimeter return paths or the final Rust label location. Keep the released renderer/router as the observation source. Do not persist computed bends/label overrides or change the cutoffs to improve this comparison. Estimated label bounds remain a planning approximation; actual text and association require later native review.
## Preservation and projection gates
Use original visible placement identities and the actual projected forest, not semantic element IDs alone. Preserve complete authored containment, semantic endpoint/port identity, direction, names, relation data, filters, fold flags, entry order and other views. Freeze reset eligibility from the pre-operation projection; use the existing audited original-to-final import/reset/retained-route translation exactly once. A no-position-change result may still perform the declared route reset and must be reported accordingly.
For a visible collapsed node, retain its compact projected dimensions exactly and preserve stored expanded size. Treat it as opaque for packing. Its promoted visible edges can influence placement without turning promoted owners into actual semantic owners. Hidden descendants follow the importer's nearest visible collapsed ancestor translation; never use local compact coordinates as their expanded geometry or relayout them secretly. Ineligible/folded route metadata remains stored with the existing translation policy, ready for expansion. Unrelated filtered/out-of-projection placements remain governed by the declared import scope. The frozen folded workshop has no nonempty authored-route sentinel: preservation there alone cannot prove suspension/restoration of arbitrary hidden pins.
Expanded containers must contain their final projected children below the appropriate header and above any footer/port-content requirement. Use the core geometry minima for the applicable projection rather than universal64-unit assumptions for all kinds. Growing a container may change relative port tips, port spacing and automatic sides; recompute the actual final projection. Final-size constraint disagreement is a failure, not a reason to overwrite anchors. Check finite positions/sizes, no illegal shrink/overlap, complete projected IDs, and exact intended versus final node geometry.
Authored port anchors and dormant explicit attachments remain exact. Automatic port-side/slot changes are geometric outputs, not automatically conservation failures. Record every change and inspect the final mandatory leads. Repeated projection/packing must not cause side or size oscillation. A lead-incompatibility rejection is useful but necessary-only: final routing must still be checked for NoClearPath, warnings, unrelated node/header penetration and identity-specific collisions.
## Falsifiers on the fixed comparison
Keep all five frozen realistic cases and all nine existing small fixtures. Report unsupported/failed cases separately from outputs; never silently substitute a flattened or unfolded version. Keep the same reset baseline and unchanged released routing, and preserve the old prototype and prior external placements as references. New fixture construction or parameter selection must not be driven by these outputs.
- **Structural diagnosis:** for sparse40, independently recover the four10-node actual SCC memberships and relate them to placement blocks. Report each component's bounding span and its condensation rank interval. A proxy implementation that still interleaves those flat components or spreads a component over unrelated global ranks does not test the proposed remedy correctly. Mixed's six-node SCC and four singletons are a second independent topology check.
- **Dominant ambiguity:** recompute pairwise interval multiplicity on the final drawing. The sparse y28 trunk contributed38880/40522 and mixed y28 contributed4006/4228. Track the same edge groups wherever they move, as well as the new global worst corridor. Removing occupancy at literal y28 while recreating comparable sharing on another boundary is not success. Report unique corridor length, distinct-edge multiplicity and raw pairwise sharing separately; do not reinterpret a distinct-port trunk as an intentional bus.
- **Tradeoffs:** report proper/T/bend/endpoint contacts, nonterminal sharing, every new/resolved label/node and label/stroke conflict, route length/bends, drawing bounds and warnings. A compact arrangement that reduces area but increases ambiguous contacts is a tradeoff, not a quality pass. A large area gain bought with unreadable label packing is also a failed hypothesis. No weighted total determines adoption.
- **Compound capability:** the original/folded workshop must receive an actual declared supported result or explicit refusal. For supported compound cases, independently inspect child/header containment, port/edge promotion and hidden metadata. Passing flat sparse/mixed does not establish this milestone's hierarchy objective. The earlier two-container crossed-child fixture is useful here: check whether block order and child order cooperate rather than simply aligning container centers.
- **Port/lead compatibility:** preserve fixed-port fixture anchors and original opposing-side meaning; do not solve the task by moving an authored port. Final absence of incompatible leads must be followed by the normal full-route warning/penetration gate. Reject a new hard routing failure even when aggregate sharing decreases.
- **Repeatability:** same input yields identical Project; ten repeated candidate calls should settle after the first accepted arrangement, with no cumulative size inflation, shifting origin, side oscillation or hidden-coordinate drift. Keep mixed's fixed relation-ID permutation and semantic correspondence. Identical pixels are not required for every graph symmetry, but new failed trace tasks or severe order sensitivity cannot be hidden by selecting favorable IDs.
All14 cases need complete accounting. The small fixtures are explanatory witnesses, not training examples whose success compensates for realistic failures. Bound component recursion, graph/work/span, and any reprojection iterations; unsupported topology and bound exhaustion must discard the private candidate without partial model changes.
## What would justify the next step
A useful result would show that coherent components materially reduce the diagnosed long shared corridors on both sparse and mixed cases, without a new hard route/containment/identity failure, while producing explicit compound results. This would support further initial coordinate-assignment work. It would not yet establish readable engineer traceability or a generally optimal planner.
If actual SCC blocks become compact but long return paths still coincide, inspect internal cycle ordering and available local corridors from that fixed output before proposing another scalar router penalty. If compound quotient cycles or final-port/lead requirements prevent a faithful placement, the failure should revise the planning interface rather than force a proxy result into the Project. Do not increase iteration limits, choose a winning rotation, or add a second packing heuristic after results merely to make this corpus pass.
Before adoption, reuse the predeclared source-to-target and label-association tasks at a common readable scale with ordinary selection/pan/zoom recorded. Include fan-out, distinct ports, cycle return and promoted endpoints. Geometry improvements, even across every frozen case, do not replace that native evidence or production history/source round trips.
@@ -0,0 +1,62 @@
# Connection corridors: next bounded #32 experiment
Decision after ae9dad54: **test jointly assigned derived separation of existing orthogonal routes on a fixed placement**, before another placement-only spacing algorithm. Keep it an isolated geometry experiment. Do not integrate it into Arrange or change the released router until the named tracing witnesses and preservation checks pass. A small shared-run separator can test an actual missing mechanism; a new set of node gaps cannot ensure that the existing router consumes those gaps.
No external claims, source changes, builds, routing runs or GUI work underpin this note. Sources are the current research routing/projection code, `auto_layout_probe/layered.rs`, and the frozen connection-layout / placement-clearance experiments.
## The decisive limitation
There is no proof that *no* placement-only method can improve shared routing: the mixed ELK placement did improve it through the released router. The stronger assumption that reserving distinct empty corridors in node placement **enforces** distinct routed lanes is false under the present interface. `RoutingSpace::new` uses obstacle boundaries; `fast_path` builds direct/one-axis alternatives; `crossing_cost` only gives coincident spans a soft cost. No placement result carries edge-to-corridor membership into routing. Two connections may still choose the same shorter trunk regardless of how much unused space was reserved elsewhere. The old layered prototype illustrates the practical risk: huge sparse/mixed shared runs despite larger gaps. The clearance repair proves terminal compatibility but sparse sharing666→761 and crossings20→22 prove that compatibility is not lane allocation.
This is not a reason to adopt an entire new engine. It is a reason to test a route-space operation whose output is actually used, rather than interpreting free space as an edge reservation.
## Material options
| Approach | What it can directly control | Unresolved failure / cost | Choice |
| --- | --- | --- | --- |
| Initial coordinate assignment with distinct connection corridors | Node order, available width/height and containment; avoids known stub incompatibility. | Without route-to-corridor constraints, released routing may ignore all lane distinctions. Adding such constraints is already a joint placement/routing interface. Global per-edge spacing can explode area. | Necessary later for insufficient corridors; not the next isolated experiment. |
| Joint derived route separation after an initial route | Actual connection strokes, with fixed tips/stubs and obstacles. Can distinguish coincident nonterminal trunks without moving nodes or changing semantic ports. | Must handle order conflicts, route topology, turns, labels and insufficient clearance; careless nudging creates collisions or touches. | Preferred next bounded diagnostic. Preserve topology and refuse difficult bundles instead of silently forcing them. |
| Improve rank/order using virtual long-edge vertices | Adjacent-layer crossing order and space occupied by edges skipping ranks; fixes a real limitation of the current prototype's node-only incoming-neighbor means. | Straight-line/layer crossing reduction is not a guarantee about orthogonal trunks chosen by the independent router. Feedback/undirected/compound edges need policy. | Next placement improvement if fixed-route separation establishes that enough useful free space exists; do not present it as a direct shared-run fix. |
## Concrete experimental interface and lifecycle
One example-only function: `separate_routes(project, diagram, final_view, original_routed) -> Result<RoutedView, Diagnostic>`. Borrow the Project and view; return only derived geometry plus explicit moved-bundle/refusal facts. Initially require a flat, unfolded, complete projected scene, all relevant automatic routes free of authored pins, and no existing NoClearPath or unrelated-node penetration. The predeclared input set includes repaired sparse ELK, both mixed ELK orderings, and the small diamond/bipartite witnesses. Keep original routing as the paired control. No node geometry or anchor changes occur during this experiment.
Final automatic ports are already settled by projection. Their tips and full18-unit leads are fixed barriers/anchors for this operation, including shared semantic endpoints. Authored port anchors and explicit endpoint attachments remain exact. Protect common same-owner/same-port leads; do not require physically impossible separation of coincident terminal ink. Distinct ports must not be merged merely because coordinates coincide. Treat any authored pinned route as wholly fixed in the initial scope; defer partial between-pin movement. Preserve its label override. Generated bends must never be written to EdgeRoute.waypoints.
If later integrated, derive it every time `route_diagram` computes geometry from the current Project, not only immediately after Arrange. Otherwise Save/reopen or an unrelated redraw would lose the result. Preview must use the same derivation and respect cached unchanged routes or explicitly invalidate the appropriate bundle; that is an integration requirement, not work needed for the first example experiment. Arrange continues to commit only selected diagram presentation geometry and its existing eligible-route reset in one history transaction. Undo/Redo, other views, dormant/promoted route metadata and original-to-final translations retain their accepted behavior.
## Minimal bounded algorithm to falsify
1. From the frozen routed polylines, find positive shared **nonterminal** spans, grouped by orientation and overlapping longitudinal intervals. Split analysis intervals at segment endpoints; retain edge and original segment identity. No routing weights change and no new search grid is introduced.
2. For each small bundle, inspect the entire connected orthogonal run/turn chain that would move. Determine available transverse bounds from actual inflated obstacles, protected terminal leads and fixed routes. Assign a consistent edge order from branch attachments on both ends; if the two end orders conflict, mark unsupported rather than concealing an unavoidable crossing through arbitrary UUID ordering. Canonical semantic/placement ties are deterministic, with explicit relation-ID permutation sensitivity retained.
3. Solve all coordinates in that bundle together: neighboring tracks get a fixed declared separation, original coordinates are preferred, and adjacent perpendicular segments extend/shorten to meet the moved tracks. Do not independently move overlapping subsegments, which would produce broken routes. Any new connector needed near a protected stub is an explicit derived orthogonal dogleg, checked in full. First scope may simply refuse bundles requiring such a connector; record how many target witnesses are thereby unsupported.
4. Use a fixed small bundle/segment bound and one deterministic pass, followed by complete recomputation of geometric validity. No iterative tweak-until-metric-improves loop. If constraints lack room, either leave that bundle exactly original with an explicit refusal or fail the whole experiment according to the predeclared case protocol; never report it as repaired. Other bundles must not be treated as non-obstacles while solving, and later changes must not invalidate earlier separation.
5. Recompute automatic label placement on final paths using the same core label placement machinery. An example cannot honestly carry old bounds onto moved paths and call the resulting label metrics final. This is the main small core seam potentially needed beyond the example: factor the existing post-route label settlement phase for reuse, without changing its policy. If parent declines that extraction initially, retain labels as fixed obstacles and label the result geometry-only; it cannot pass label-aware Arrange acceptance.
This is a bounded parallel-segment constraint problem, not a whole orthogonal graph drawing framework. Avoid promoting a speculative reusable solver before one small bundle and one realistic scene demonstrate value. If the smallest useful bundle requires pervasive topology changes, stop and record that limitation; the next candidate is explicit corridor-aware routing coupled to placement, not hundreds of ad hoc bend exceptions.
## Finite evaluation and stop conditions
Use fixed geometry with an analytically separable two-route shared middle span and immutable terminal leads; a shared-port witness must retain its common lead while separating only beyond it. Include a too-narrow corridor (explicit refusal), opposite branch order (refusal or explicitly counted crossing), one fixed pinned route, and one real sparse shared-run bundle. Pair with diamond/bipartite and both mixed relation-ID variants already available. No parameter sweep.
Require exact Project, node geometry, semantic ports and endpoint tips/stubs; every output orthogonal; no new unrelated node/lead penetration, no lost hard pin, no newly introduced improper self-overlap/degenerate backtracking. Compare actual shared-run identities/lengths, proper and T/bend contacts, and label/stroke/label-node collisions after label settlement. The concrete user-facing target is tracing two formerly coincident connections from their branch points without an ambiguous shared middle run. A native trace task is still needed before adoption; an export diagram can provide review evidence but not replace interaction.
Success means at least the declared bundle and one realistic route-tracing witness separate with no new hard violation or label interference and a recorded acceptable path/area cost. A lower total shared length obtained by moving ambiguity to a different pair is failure. Idempotence means applying the separator to its own derived result makes no further change; Save/reopen recomputation from the same Project must match the original derived output. Do not claim full Arrange support: nested ancestor headers, folded promotions, undirected branch ordering and partial authored-pin routing are explicit later gates. Semantic direction is not invented for undirected edges; separator ordering derives from geometry and endpoints, and reversing an undirected edge must not change its physical lane assignment.
Stop after this fixed candidate is compared. If it only works by moving nodes, consumes excessive space, or fails the real witness because free corridors cannot preserve branch order, that is actionable evidence for a combined rank/order + corridor assignment planner. Virtual long-edge vertices then become part of routing constraints shared with coordinate assignment, rather than another placement proxy whose route result is assumed.
## Revision after grouped-sharing/SCC diagnosis
**Priority revised: SCC condensation with compact block placement is the justified next experiment; defer the joint separator.** This supersedes the initial next-action recommendation above, while preserving its alternatives and interface warning. New evidence is `connection-corridor-sharing-diagnosis-20260925.md` and its independently reconstructed interval/SCC data. The predeclared implementation contract is `harness/experiments/scc-placement-20260925/plan.md`.
The diagnosis resolves an uncertainty that my initial recommendation left too broad. Sparse has four ten-member SCCs interleaved over16 ranks;38880/40522 shared units (95.95%) occupy the same y28 outside corridor. Mixed has4006/4228 (94.75%) there. These are long stretched feedback/forward routes caused by incoherent component ranking plus aligned row boundaries and globally inflated gaps, not primarily the small local lane collision exhibited by repaired ELK geometry. A joint separator would treat a large structural symptom while retaining avoidable rank spans. Coherent condensation order and compact SCC membership directly change the implicated cause with the released router unchanged.
The frozen plan is a meaningful distinct candidate: SCCs per actual sibling quotient, condensation DAG ranks, compact perimeter for cyclic members, local label gaps, explicit final projection/lead checks and no iterative rescue. It is more appropriate now than virtual long-edge vertices: dummy vertices can improve ordering across coherent ranks but cannot undo an incorrectly split/interleaved SCC rank assignment. Among block rows and a compact perimeter, the predeclared perimeter is a reasonable single hypothesis because it bounds cyclic-member extent and distributes turn opportunities; it is **not** a proven cycle embedding. A strongly connected group need not be one simple cycle, directed DFS successor order need not make every adjacent perimeter pair connected, and chords can still cross or share trunks. Do not describe the perimeter as an optimal cycle layout.
Specific plan risks to retain in evaluation: a minimum30-unit gap only addresses a particular facing-port clearance case, not all final automatic-port choices; nested quotient SCCs are not leaf semantic SCCs; undirected edges must retain direction-free treatment and still be observed for routing quality; fixed anchors can oppose perimeter flow; expanded/folded footprints and local-label estimates must not induce repeated size growth. The plan's explicit final reprojection failure and original-to-final import policy address these as boundaries rather than silently assuming success. Header/enclosure checks and ten-call stability are essential, as declared.
The decisive falsifier is not merely fewer global ranks. Require coherent condensation order, reduced component span and the diagnosed top-corridor contribution, with no new hard geometry violation or comparable ambiguity shifted to another axis/pair. Retain area, labels, contacts and actual named trace tasks. If the perimeter introduces another outside shared loop or rejects a real case because of mandatory leads, preserve that counterexample without parameter tuning. Then select long-edge ordering for rank/order failure, or joint derived separation for a genuinely local residual channel failure.
Nothing here proves placement alone always enforces distinct lanes: that earlier interface limitation remains exact. Nor does the diagnosis prove that a coupled router is necessary. It supplies a narrower, more causal and cheaper first experiment than the initial separator recommendation. No new run or implementation was performed for this revision.
@@ -0,0 +1,54 @@
# Corridor sharing diagnosis
Read-only UTF-8 analysis of frozen `elk-reference-20260925/rust-run03/arrange-corpus/stdout.jsonl` and `placement-clearance-20260925/run02/subsystems_40_sparse-elk/stdout.jsonl`. No engine/router/compiler/native execution. Full source hashes, grouped intervals, edge identities/names/endpoints/sides, largest pairs and independently reconstructed SCC/ranks are in `connection-corridor-sharing-groups-20260925.json` (SHA256 `f9114eaafa22f1d618783b4a62a570d24387645451aafc2123561b53ed16968f`).
## Main finding
**The dominant layered failure is rank stretching plus aligned obstacle-boundary corridors. SCC-aware placement is a more direct first controllable experiment than requiring a joint routing engine.** Routing channel choice contributes, but these records do not show that a coupled router is necessary. They also do not prove that any proposed SCC packing will improve the full metric vector.
Independent sweep: group all positive orthogonal segments by axis and fixed coordinate, split at every endpoint, count distinct edge identities on each atomic interval, and accumulate length × choose(edge count,2). This exactly reproduces all four raw shared-length totals. Edge contribution counts each incident pair once per edge, so summing contributions doubles the total; this is not unique physical ink length.
| Scene | Raw pairwise sharing | Horizontal | Vertical | Common-terminal excluded |
|---|---:|---:|---:|---:|
| Sparse layered |40522|39174|1348|0|
| Mixed layered |4228|4042|186|54|
| Sparse ELK placement + Rust |666|0|666|0|
| Sparse clearance repair + Rust |761|0|761|0|
All four scenes are flat: no visual parents or compound-header explanation. Sparse sharing is entirely nonterminal; mixed remains4174 after the54 common-terminal units. Shared endpoint ownership is not itself a common physical terminal: distinct port channels remain distinct connections.
## Sparse: five long routes crowd the same top boundary
At y28 alone, shared pairwise length is38880, 95.95% of40522. This is exactly the top y40 node row minus12 clearance. The dominant interval x1746..3926 has five edges over2180 units, contributing21800 pairwise units. Adjacent x3926..5878 has four edges and contributes11712; x1258..1746 has four and contributes2928. Thus a few continuous outside runs, not thousands of independent intersections, dominate the score.
Five edges on the largest interval:
- `flow_15` Assessment Decode to Validate: source x528,y40 Right → target x5896,y40 Left; total incident sharing17046.
- `flow_16` Assessment Validate to Enrich: x5896,y40 Left → x40,y220 Right;17890.
- `flow_41` Communications Decide handoff to Assessment Aggregate: x6384,y40 Left → x40,y428 Right;18676, the maximum contributor.
- `flow_42` Communications Publish handoff to Assessment Package: x7360,y40 Left → x1016,y220 Right;16590.
- `flow_46` Assessment Publish handoff to Planning Package: x1504,y40 Right → x3944,y40 Left;8720.
These are distinct semantic ports, not a legitimate shared bus. Both forward long edges and backwards edges use the same corridor. Automatic side selection follows the stretched final geometry; sparse has no authored anchors to explain those choices.
Independent directed reachability finds **four SCCs of10 nodes**, not one40-node SCC. Reproducing the prototype's alias-ordered cycle breaking yields16 global ranks and exactly the observed x positions40,528,…7360 (488 pitch =224 node width +264 global gap). SCC members span ranks0..9,0..12,0..13 and2..15: components are interleaved and stretched rather than treated as compact units. Cycle breaks are Assessment Acquire, Assessment Aggregate, Assessment Enrich and Assessment Package. Source `layered.rs::ranks` breaks the first canonical remaining vertex even if an upstream SCC is still cyclic; later longest-path assignment uses already assigned predecessors. Thus even edges between different SCCs can become long backward connections in the resulting global order.
The global horizontal gap is derived from the maximum estimated edge-label width plus24, rather than local edge needs. It multiplies the cost of long rank spans. Three incoming-neighbour ordering passes only sort existing ranks; they cannot repair rank assignment, and do not introduce virtual vertices for long edges. Source `place` starts each rank at the same top y40, supplying a common outer obstacle boundary. This chain explains the geometry without attributing the entire problem to a routing coefficient.
## Mixed: same mechanism at smaller scale
Mixed has one6-node SCC plus four singletons. The SCC spans ranks1..6; the whole graph uses seven ranks with474 pitch (224+250 global gap). Cycle breaks Actuator, Archive and Correlate include an initially blocked singleton, again showing that canonical cycle breaking is not condensation-DAG ordering.
At y28, three dominant routes contribute4006/4228 (94.75%). Interval x1230..2178 carries `flow_04` Validated observations, `flow_08` Actuator dispatch and `flow_10` Operator acknowledgement:948×3=2844. Another948-unit interval carries dispatch/acknowledgement; the final214 units carry validated observations/acknowledgement. The largest contributor is acknowledgement3212; dispatch2892, validated observations2110. Unlike sparse, Dispatch's Right port is authored, so any future layout must honor that side rather than solving the overlap by changing its anchor.
## ELK and repair are a different, local channel issue
The666→761 increase has no horizontal sharing. Largest unchanged interval is x8517,y938..1030: three edges (`flow_12`,`flow_17`,`flow_38`) contribute276; this is18 units left of target-column x8535. Some terminate on different ports of Communications Package; another targets Assessment Aggregate, so the full interval is not common-terminal reuse.
Exact pairwise delta decomposition: `flow_19/flow_42` gains152; `flow_30/flow_51` loses11; `flow_50/flow_53` loses57; `flow_29/flow_48` gains11. Net95. The new152-unit channel is x4504,y526..678, again18 units left of x4522. This is a side effect of changed placement and derived rerouting after clearance repair, not persistence of the huge layered top trunk.
The released router processes routes sequentially and uses a soft collinear penalty min(overlap×0.12,80) per occupied segment; this is not a global no-sharing allocation rule. That source fact explains why channel reuse remains permitted, but does not establish why every alternative was rejected or that changing the penalty is the right solution. No cost tuning follows from this diagnosis.
## Next falsifiable comparison
Freeze these same input graphs and unchanged released routing. First compare an SCC-condensation ordering with explicit local packing/feedback treatment against the current alias cycle break. Preserve semantic ports/anchors and evaluate actual reprojection, rank span, backwards-edge span, shared interval multiplicities, crossings, labels, area and leads. Failure to reduce the y28 corridor without trading it for comparable hidden contacts/area falsifies the proposed structural benefit. A separate long-edge virtual-vertex ordering experiment is meaningful after ranks are coherent; it cannot by itself repair the present stretched SCC assignment. Local channel allocation can then be evaluated for the residual ELK/repair vertical runs at fixed geometry. Neither stage should be declared necessary or successful before measurement.
@@ -0,0 +1,851 @@
{
"schema": 1,
"source_commit": "2426d286483ab0445663221cd6010a3dadb89a97",
"archive": {
"file": "scc-placement-2426d286.zip",
"bytes": 6041259,
"sha256": "fbf40882ed807a1b40db8b3b9b9c846b060db02cbcc60611c18f9620c1fd59c9"
},
"members": [
{
"member": "collector/archive-scc-placement-20260925.py",
"bytes": 3887,
"sha256": "bcf1910bd5110c3c14c5bf4dd612fd65d2c686f8d9a5d45405b58ec7c5b1b486"
},
{
"member": "collector/run-routing-corpus-check-20260925.py",
"bytes": 2793,
"sha256": "2726a397bd4ecb4dcfff6fc170a66ce2655229079f42335faa2a4bfe4a202f6d"
},
{
"member": "collector/run-scc-placement-20260925.py",
"bytes": 3628,
"sha256": "40c33c2703768eaa512553322ccc628fbdc3630c2968c4cc8ce127a6c6714757"
},
{
"member": "collector/write-scc-results-20260925.py",
"bytes": 9848,
"sha256": "ad2ea7ac903f5557c2e5d522d04ea0a589b991ed3ca7c0840ec40d04d42d38ef"
},
{
"member": "gates/18-scc-example-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/18-scc-example-tests/command/context.json",
"bytes": 3505,
"sha256": "a38ff5f35a5578eb37f41bf2b6487634813861025bc3ad4d125251605f223a12"
},
{
"member": "gates/18-scc-example-tests/command/inputs-after.json",
"bytes": 1755092,
"sha256": "9e23948f6a23224909279ed38c366f45ff472aaf7c3dd94be74b5cd8ea3637e7"
},
{
"member": "gates/18-scc-example-tests/command/inputs-before.json",
"bytes": 1755092,
"sha256": "9e23948f6a23224909279ed38c366f45ff472aaf7c3dd94be74b5cd8ea3637e7"
},
{
"member": "gates/18-scc-example-tests/command/output.log",
"bytes": 440,
"sha256": "3510acc240220b72c1269b9b927656cd426fc4d62c975d96d13d50889e245943"
},
{
"member": "gates/18-scc-example-tests/command/result.json",
"bytes": 4168,
"sha256": "97d627584143e47a0bde6154edaaf403c07d248b60fc47cd3ffe1f6f8bb4f1e4"
},
{
"member": "gates/18-scc-example-tests/command/stderr.log",
"bytes": 336,
"sha256": "8e11399e5c28b4f0b364568f06d4922bfca59fb7b1dd0c4c73df3f88d60257ad"
},
{
"member": "gates/18-scc-example-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/18-scc-example-tests/orchestration.log",
"bytes": 180,
"sha256": "fdad0fe87d49b532b04b2612c3bde4f1a3114e12613189bb91952469bc635825"
},
{
"member": "gates/19-scc-corrected-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/19-scc-corrected-tests/command/context.json",
"bytes": 3507,
"sha256": "6030b5f305c844259023aae178f5cc99ec8d6af4b45582f2e333fc52a4061a00"
},
{
"member": "gates/19-scc-corrected-tests/command/inputs-after.json",
"bytes": 1755092,
"sha256": "53a042b82d8a6ce79de30e6bc6cfdc71f32e7762a82373ce1315423b5e5eae39"
},
{
"member": "gates/19-scc-corrected-tests/command/inputs-before.json",
"bytes": 1755092,
"sha256": "53a042b82d8a6ce79de30e6bc6cfdc71f32e7762a82373ce1315423b5e5eae39"
},
{
"member": "gates/19-scc-corrected-tests/command/output.log",
"bytes": 536,
"sha256": "833b6716dd2533562e8faa1062259da5b4d3ba2ebd89cd67393900b97b4c739c"
},
{
"member": "gates/19-scc-corrected-tests/command/result.json",
"bytes": 4174,
"sha256": "d6905113e765158dbfb9cbfb4c87f6c8eff7f36337a2e7b2845b5d51ef72ee71"
},
{
"member": "gates/19-scc-corrected-tests/command/stderr.log",
"bytes": 336,
"sha256": "4c991e05c9de1d64fd1747c686af26eec1f97a27c3626001fd900de70b60fa6b"
},
{
"member": "gates/19-scc-corrected-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/19-scc-corrected-tests/orchestration.log",
"bytes": 182,
"sha256": "314d9dd697a24da445f8e4533eb7b14197cdcff58d260b0a667fa9c0b00962b2"
},
{
"member": "gates/20-scc-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/20-scc-clippy/command/context.json",
"bytes": 3535,
"sha256": "3a999e9dd4d245bc01b9b264273e8525818b4892766deef6527bcdcd26c64e20"
},
{
"member": "gates/20-scc-clippy/command/inputs-after.json",
"bytes": 1755092,
"sha256": "53a042b82d8a6ce79de30e6bc6cfdc71f32e7762a82373ce1315423b5e5eae39"
},
{
"member": "gates/20-scc-clippy/command/inputs-before.json",
"bytes": 1755092,
"sha256": "53a042b82d8a6ce79de30e6bc6cfdc71f32e7762a82373ce1315423b5e5eae39"
},
{
"member": "gates/20-scc-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/20-scc-clippy/command/result.json",
"bytes": 4184,
"sha256": "b8aec050f2e1b5074717edede43ff3acfb3f42d251376e54fa116b16c09b47c9"
},
{
"member": "gates/20-scc-clippy/command/stderr.log",
"bytes": 830,
"sha256": "836381446c6b5aa7b0d0bd4e1321375595cf6f4001390e37c6042a3ae8a8ccbc"
},
{
"member": "gates/20-scc-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/20-scc-clippy/orchestration.log",
"bytes": 175,
"sha256": "82805760283baab8da36de90c204a723f71d90e00eb33d6cab99f58c9e89053c"
},
{
"member": "gates/21-scc-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/21-scc-tests/command/context.json",
"bytes": 3497,
"sha256": "e2ab8c21c637919f4e8d6e2d1ecea96289165bacdc468b8b0dd870977c6193d7"
},
{
"member": "gates/21-scc-tests/command/inputs-after.json",
"bytes": 1755092,
"sha256": "3c16e04dbe3215742da10626cd465e68cf32ccb7685b2bc5ab084548e70c30cb"
},
{
"member": "gates/21-scc-tests/command/inputs-before.json",
"bytes": 1755092,
"sha256": "3c16e04dbe3215742da10626cd465e68cf32ccb7685b2bc5ab084548e70c30cb"
},
{
"member": "gates/21-scc-tests/command/output.log",
"bytes": 536,
"sha256": "833b6716dd2533562e8faa1062259da5b4d3ba2ebd89cd67393900b97b4c739c"
},
{
"member": "gates/21-scc-tests/command/result.json",
"bytes": 4144,
"sha256": "5611dc41970a0f2ca240a7bd32aa8261851b05026a6df1ad85dcb0ce26735ebd"
},
{
"member": "gates/21-scc-tests/command/stderr.log",
"bytes": 336,
"sha256": "4eb583fbb1c6eb53b6fd0a17ef6a8faef02c5e5a678459d78ff101dc597db837"
},
{
"member": "gates/21-scc-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/21-scc-tests/orchestration.log",
"bytes": 172,
"sha256": "ecfa25a2732e5b5f2c7e9cf457de494dd89c43e8ba64d2caffebef38ef288185"
},
{
"member": "gates/22-scc-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/22-scc-clippy/command/context.json",
"bytes": 3535,
"sha256": "7641413d4d7712c0a1070e9634cd8b28bcc7f827c225ebda55aac45ce9208da0"
},
{
"member": "gates/22-scc-clippy/command/inputs-after.json",
"bytes": 1755092,
"sha256": "3c16e04dbe3215742da10626cd465e68cf32ccb7685b2bc5ab084548e70c30cb"
},
{
"member": "gates/22-scc-clippy/command/inputs-before.json",
"bytes": 1755092,
"sha256": "3c16e04dbe3215742da10626cd465e68cf32ccb7685b2bc5ab084548e70c30cb"
},
{
"member": "gates/22-scc-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/22-scc-clippy/command/result.json",
"bytes": 4182,
"sha256": "39395b4dcf3c66f3e490cd6bb4d2fa8f4ac40ba5ffd46708287f9012cd9b61a9"
},
{
"member": "gates/22-scc-clippy/command/stderr.log",
"bytes": 176,
"sha256": "7be90bc986d32ae1b1f4bf7e877bbcb73389e60288af76e6af2b6626e8cd2626"
},
{
"member": "gates/22-scc-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/22-scc-clippy/orchestration.log",
"bytes": 173,
"sha256": "3ff1bf85e86dabef766aad475314f4134a0cf663887bb74785ed8373b536b5ae"
},
{
"member": "gates/23-scc-release/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/23-scc-release/command/context.json",
"bytes": 3524,
"sha256": "a7f20125d78395643742fe1157d883f001d1d94e53697ca9c469ddb3340a7531"
},
{
"member": "gates/23-scc-release/command/inputs-after.json",
"bytes": 1755092,
"sha256": "3c16e04dbe3215742da10626cd465e68cf32ccb7685b2bc5ab084548e70c30cb"
},
{
"member": "gates/23-scc-release/command/inputs-before.json",
"bytes": 1755092,
"sha256": "3c16e04dbe3215742da10626cd465e68cf32ccb7685b2bc5ab084548e70c30cb"
},
{
"member": "gates/23-scc-release/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/23-scc-release/command/result.json",
"bytes": 4173,
"sha256": "3e5adf5bad50cacfdb02b10568d3699531e365380682fd247bc7e43df112b21a"
},
{
"member": "gates/23-scc-release/command/stderr.log",
"bytes": 179,
"sha256": "cd616b849f5be8e680183b2ec2fee33ca301a0151ddde93fcb2947a512bc287a"
},
{
"member": "gates/23-scc-release/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"member": "gates/23-scc-release/orchestration.log",
"bytes": 174,
"sha256": "bebcb80f84dc83fa0f718f41203fd3cdf52b70b2c7636fca4d1b432924c89d5f"
},
{
"member": "gates/24-scc-transfer-tests/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/24-scc-transfer-tests/command/context.json",
"bytes": 3506,
"sha256": "de2ae28d115235da55dd61bea562a752d982b27730ea30ebfecaee5aca972ecd"
},
{
"member": "gates/24-scc-transfer-tests/command/inputs-after.json",
"bytes": 1755092,
"sha256": "67557a240c92ce4b7d9395dccf4d8c783c95012b5ed04b3836e511117c34ae65"
},
{
"member": "gates/24-scc-transfer-tests/command/inputs-before.json",
"bytes": 1755092,
"sha256": "67557a240c92ce4b7d9395dccf4d8c783c95012b5ed04b3836e511117c34ae65"
},
{
"member": "gates/24-scc-transfer-tests/command/output.log",
"bytes": 810,
"sha256": "ada006a93f2d7512c1134d58dc3a163f1c3203e05812192ab267143979ba931e"
},
{
"member": "gates/24-scc-transfer-tests/command/result.json",
"bytes": 4171,
"sha256": "872ae3bfb6f724d53c3b82eb158df3bb402154ae3e8f08283c39b6256f84a915"
},
{
"member": "gates/24-scc-transfer-tests/command/stderr.log",
"bytes": 336,
"sha256": "f580a0e0f692d052343e2f196ee8b7506c89d0cf423ca1e261cc8388abbeaef6"
},
{
"member": "gates/24-scc-transfer-tests/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/24-scc-transfer-tests/orchestration.log",
"bytes": 181,
"sha256": "aa10d2e705dfe95b2a1aa57aaa630e474c98247216d85dc7011173ae2f86c1e8"
},
{
"member": "gates/25-scc-transfer-clippy/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/25-scc-transfer-clippy/command/context.json",
"bytes": 3544,
"sha256": "54ef12b091c100fe7e4dc15eb7f51160a4a30e8f3b716c021921c41acdc7df54"
},
{
"member": "gates/25-scc-transfer-clippy/command/inputs-after.json",
"bytes": 1755092,
"sha256": "67557a240c92ce4b7d9395dccf4d8c783c95012b5ed04b3836e511117c34ae65"
},
{
"member": "gates/25-scc-transfer-clippy/command/inputs-before.json",
"bytes": 1755092,
"sha256": "67557a240c92ce4b7d9395dccf4d8c783c95012b5ed04b3836e511117c34ae65"
},
{
"member": "gates/25-scc-transfer-clippy/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/25-scc-transfer-clippy/command/result.json",
"bytes": 4209,
"sha256": "7b037ce78415017a21577e32bda7c73b1658e222d53753cc00b53bf2ab74b510"
},
{
"member": "gates/25-scc-transfer-clippy/command/stderr.log",
"bytes": 176,
"sha256": "ec857d6226e95672a08768dfbd776562e3e9c329f9031c660c407d64edb1f452"
},
{
"member": "gates/25-scc-transfer-clippy/environment.json",
"bytes": 9466,
"sha256": "d9d984528a82c0db3c2e009db91104d7b7c1233921793802bbeb87677f35daf8"
},
{
"member": "gates/25-scc-transfer-clippy/orchestration.log",
"bytes": 182,
"sha256": "7fd6a5c356f4640a43faf5c91c01327f995a4d93f93c0a9b508ef6131a03c26d"
},
{
"member": "gates/26-scc-transfer-release/command/changes.patch",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/26-scc-transfer-release/command/context.json",
"bytes": 3533,
"sha256": "46588f276ededd1c28852659b30af3b13d074421a134106a0b75679f0a50d379"
},
{
"member": "gates/26-scc-transfer-release/command/inputs-after.json",
"bytes": 1755092,
"sha256": "67557a240c92ce4b7d9395dccf4d8c783c95012b5ed04b3836e511117c34ae65"
},
{
"member": "gates/26-scc-transfer-release/command/inputs-before.json",
"bytes": 1755092,
"sha256": "67557a240c92ce4b7d9395dccf4d8c783c95012b5ed04b3836e511117c34ae65"
},
{
"member": "gates/26-scc-transfer-release/command/output.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "gates/26-scc-transfer-release/command/result.json",
"bytes": 4200,
"sha256": "1e531e586f3ee85a502186662fa97cd67119229554edd46ccbc2175d4af36bdc"
},
{
"member": "gates/26-scc-transfer-release/command/stderr.log",
"bytes": 179,
"sha256": "c09d2543f7352e8fa827be3f41debe0d84b7fec666e8b2d27f3f4d0693a6a07a"
},
{
"member": "gates/26-scc-transfer-release/environment.json",
"bytes": 9470,
"sha256": "1cda80470e5893747b1aad7eda5ef51d57069441e810698cd7f94f7a7521bfe5"
},
{
"member": "gates/26-scc-transfer-release/orchestration.log",
"bytes": 183,
"sha256": "39f7e83972586ac72325f0a1a9275c778b92af4e05c412c216c32c108657caca"
},
{
"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": "reviews/audit-scc-conservation-20260925.py",
"bytes": 11022,
"sha256": "7ebe5726c49c0918a9fbd55f74e16cac484ccec9d13f9cada7a7b36672ff1035"
},
{
"member": "reviews/audit-scc-conservation-v2-20260925.py",
"bytes": 14082,
"sha256": "66a1621ac04e73bf08637047ed623c7154c0219a3076be7246004e6bf134d4e2"
},
{
"member": "reviews/audit-scc-placement-20260925.py",
"bytes": 7233,
"sha256": "9990be4df625d3f6e566502c4abd1672fc1a8e0077017ef17b98e8c8dfdaa2f5"
},
{
"member": "reviews/audit-scc-placement-v3-20260925.py",
"bytes": 8729,
"sha256": "8b238f010eeb81720a59a0ad290544f87934acb8070e58a3fd25f9eda9f47a0d"
},
{
"member": "reviews/connection-corridor-design-20260925.md",
"bytes": 14520,
"sha256": "02953ef1ae84c83b8c2c7f3b539c6be147ca2ae43f7dd94cf3836ff6f8ee3b30"
},
{
"member": "reviews/connection-corridor-sharing-diagnosis-20260925.md",
"bytes": 7467,
"sha256": "506bbec69bbe229161547906452fe11fb00a7fa8e46023ed3dcb0e2301f8fecb"
},
{
"member": "reviews/prior-sharing-groups.json",
"bytes": 88110,
"sha256": "f9114eaafa22f1d618783b4a62a570d24387645451aafc2123561b53ed16968f"
},
{
"member": "reviews/scc-conservation-audit-20260925.json",
"bytes": 44150,
"sha256": "736d0269bf7cab453abc150a12eece22cb3bc2372c3a3a173638d8aa7a84817e"
},
{
"member": "reviews/scc-conservation-audit-final-20260925.json",
"bytes": 46033,
"sha256": "c9156b710323d940a712ca8973a2e823a422faf96ad9c509193968ecf2f7fdd9"
},
{
"member": "reviews/scc-conservation-audit-run02-20260925.json",
"bytes": 51903,
"sha256": "2897af5f3d131e2633a8dc5c9385307516c7c4db227349b374d4d062423a425e"
},
{
"member": "reviews/scc-conservation-audit-v2-20260925.json",
"bytes": 44876,
"sha256": "fc1a1b0c5a5b9905b54c28f4719fd5ae9c5fcc998939f146523a2296375c9013"
},
{
"member": "reviews/scc-conservation-review-20260925.md",
"bytes": 3912,
"sha256": "4fa505eb8fdcda3a9225b363cb127755ae241809a7a07212b80a8d52513ac681"
},
{
"member": "reviews/scc-conservation-review-run02-20260925.md",
"bytes": 2963,
"sha256": "bdcd203edf2ba002d530d6d7e72b7cb2baeec9207b5b4c8de409dfdb5348214b"
},
{
"member": "reviews/scc-failure-diagnosis-20260925.md",
"bytes": 8906,
"sha256": "7a866902303fb83d14a673e1cede028c5a15517499e8e5f284fced4212f9a536"
},
{
"member": "reviews/scc-placement-criteria-20260925.md",
"bytes": 10647,
"sha256": "f2872610e5f78e2ccec8b487c2ac873505ecab8ad5f876f741142299fefab993"
},
{
"member": "reviews/scc-placement-implementation-20260925.md",
"bytes": 4776,
"sha256": "3436bf1cb500a72b4625ecb022b2035f67d08d909e9d5c9249ea676bc25a30cb"
},
{
"member": "reviews/scc-placement-independent-audit-20260925.json",
"bytes": 184175,
"sha256": "10e53afa7e19cf90cd66524451a2bf4723d98abcca8b1b1c4503d466e19c3df2"
},
{
"member": "reviews/scc-placement-independent-audit-run02-20260925.json",
"bytes": 200406,
"sha256": "cb1caa9b87a02ec9cdc793360b1d699e646fbe89605cd09dd578fe77440aed39"
},
{
"member": "reviews/scc-placement-independent-audit-v2-20260925.json",
"bytes": 193211,
"sha256": "519baf9fa49238aaa1e2b61e44b1c0e6b9d420b2ed7dcafe7b489d9e01396682"
},
{
"member": "reviews/scc-placement-result-review-20260925.md",
"bytes": 8052,
"sha256": "48fbac747679069e0d1d3d713cba6c65cf3d4d3cde220ac8ca939525fd8eec89"
},
{
"member": "reviews/scc-placement-result-review-run02-20260925.md",
"bytes": 4300,
"sha256": "c07bb1c43f0666f59dd6fecdd63b806ea35e3485db197f9b99caa1ec551f947c"
},
{
"member": "reviews/scc-placement-source-review-20260925.md",
"bytes": 10597,
"sha256": "24e496c3050b4d5cbbd1abaf2bf4587642cdfc742e245a2f041ba43ed2cce114"
},
{
"member": "reviews/scc-placement-source-review-v2-20260925.md",
"bytes": 5402,
"sha256": "fb3ac17e52f2c3a6cbfded78d2d72d64b4b15b388f4fdb943d7eb5b28d5d45ca"
},
{
"member": "run01/capture.json",
"bytes": 4068,
"sha256": "060fbf28e59dc7fceba30b856b1877efab8058381a5ae9363e20129005208015"
},
{
"member": "run01/mixed_dispatch/receipt.json",
"bytes": 1102,
"sha256": "69721d3e295a9a987da0333840c3ba5355ee0f24669ff071223f48e149e8026d"
},
{
"member": "run01/mixed_dispatch/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch/stdout.jsonl",
"bytes": 93898,
"sha256": "28a7f598746f4c0c58afd0321861e417b2715976cde52bf55361dce8c35b4d74"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed/receipt.json",
"bytes": 1173,
"sha256": "548fe7ca1e8c40b837de8e0490793f44e42661b28486065161138ae3b5bb6026"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/mixed_dispatch_edge_ids_reversed/stdout.jsonl",
"bytes": 93308,
"sha256": "6a723a4899026c2df80327fb76c5dda8e5dc5e4e15e9e066991413c2246bade5"
},
{
"member": "run01/receipt.json",
"bytes": 15627,
"sha256": "f84bc9793636a9bb087d465d2d9bb22b39a3bc6ccae595fc60438db4b0c03f18"
},
{
"member": "run01/route-control/receipt.json",
"bytes": 1047,
"sha256": "6e744db4c7ceee5f93bfdbf3bfcdf3057443c7dbc42da385356f90239e6e982b"
},
{
"member": "run01/route-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/route-control/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "run01/small-controls/receipt.json",
"bytes": 866,
"sha256": "4a3b959ea27cefd67989ded74d4b3990236e1261a70ee4b98aead65e33ef4074"
},
{
"member": "run01/small-controls/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/small-controls/stdout.jsonl",
"bytes": 425661,
"sha256": "0ec2bc1f51542b41b5df0b89d2a87306716a49a22951c4dfeb128dd75247d074"
},
{
"member": "run01/small-scc/receipt.json",
"bytes": 874,
"sha256": "553e8a1840e44f2e14b11d24397b2434e7d6b9d2d14ac5accb8b1a0233d0ebca"
},
{
"member": "run01/small-scc/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/small-scc/stdout.jsonl",
"bytes": 205873,
"sha256": "b35cbe482f8ad23da068da5761bdc61cfb88de3b1fa982f90ce78f5e379c9742"
},
{
"member": "run01/subsystems_40_sparse/receipt.json",
"bytes": 1125,
"sha256": "7b60517dc2323d9834aa765580c5b6ffadae22f10840d5a7db5c9d58f2108577"
},
{
"member": "run01/subsystems_40_sparse/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/subsystems_40_sparse/stdout.jsonl",
"bytes": 361147,
"sha256": "452690f23dda57f62d115b6d88e42d7f0283b4c86081d5149d8738ba6052e53b"
},
{
"member": "run01/workshop_sa_folded/receipt.json",
"bytes": 1118,
"sha256": "c03d5851dea753a00884763c1201e742ba1e53bf49e112d27c03ccd58e178cc8"
},
{
"member": "run01/workshop_sa_folded/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_folded/stdout.jsonl",
"bytes": 194613,
"sha256": "ddf05a2ca36950305090bd5d91ec2a6c617d2eae373c33ad84e9ff4157581c0c"
},
{
"member": "run01/workshop_sa_original/receipt.json",
"bytes": 1126,
"sha256": "109d91b60376fb5d040bf4502a438a343df438a760e6cdef2d61fdabe40f7edb"
},
{
"member": "run01/workshop_sa_original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run01/workshop_sa_original/stdout.jsonl",
"bytes": 198272,
"sha256": "e30a2a6a30d1522cb2f8e9377e7eb8f0a81d1fe8b5aa18550f78c4829b8cc408"
},
{
"member": "run02/capture.json",
"bytes": 4086,
"sha256": "f077c04496d69ed9b9dcc775cd9dfecd0155938d9a4dc85309d8d7a20e14f18b"
},
{
"member": "run02/mixed_dispatch/receipt.json",
"bytes": 1100,
"sha256": "15d3cc1d5885e19551dce4de7a49760551c2fd339326dbf3def9f578dd6a10da"
},
{
"member": "run02/mixed_dispatch/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch/stdout.jsonl",
"bytes": 93898,
"sha256": "28a7f598746f4c0c58afd0321861e417b2715976cde52bf55361dce8c35b4d74"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed/receipt.json",
"bytes": 1173,
"sha256": "04ccd337cc5faff73128a8878b68fa14ccc2df8587daaa20fe0dfd1be244c71e"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/mixed_dispatch_edge_ids_reversed/stdout.jsonl",
"bytes": 93308,
"sha256": "6a723a4899026c2df80327fb76c5dda8e5dc5e4e15e9e066991413c2246bade5"
},
{
"member": "run02/receipt.json",
"bytes": 15643,
"sha256": "30e39e35f606d81b280608c8091d8a93b6d3abf474cba98aac530ee438de5129"
},
{
"member": "run02/route-control/receipt.json",
"bytes": 1047,
"sha256": "6856288ab2bb710040764c08abab12aea3201315749259a8d59942a06dc96549"
},
{
"member": "run02/route-control/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/route-control/stdout.jsonl",
"bytes": 470144,
"sha256": "9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2"
},
{
"member": "run02/small-controls/receipt.json",
"bytes": 866,
"sha256": "eb8e2c5d6aaaf93c46e03a55329fc1cb412552e83e50cffbc735e835b6b662bd"
},
{
"member": "run02/small-controls/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/small-controls/stdout.jsonl",
"bytes": 425661,
"sha256": "0ec2bc1f51542b41b5df0b89d2a87306716a49a22951c4dfeb128dd75247d074"
},
{
"member": "run02/small-scc/receipt.json",
"bytes": 874,
"sha256": "129709582dc204fe281f89d4e6a2ff29ba43cb3991d9c5808ecd92e392a9ea3d"
},
{
"member": "run02/small-scc/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/small-scc/stdout.jsonl",
"bytes": 220188,
"sha256": "0c8b9ef7888cd5ba99733f15d22478cdb2878ef02e22d297d02c8b3eea2e9e15"
},
{
"member": "run02/subsystems_40_sparse/receipt.json",
"bytes": 1125,
"sha256": "4814cc9f9583f1a8994a6cb70b04c4a3fbbbf5d5bb5fa5259bb297e19241cae3"
},
{
"member": "run02/subsystems_40_sparse/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/subsystems_40_sparse/stdout.jsonl",
"bytes": 361147,
"sha256": "452690f23dda57f62d115b6d88e42d7f0283b4c86081d5149d8738ba6052e53b"
},
{
"member": "run02/workshop_sa_folded/receipt.json",
"bytes": 1118,
"sha256": "b943c33a5ae497a34186fcc5a7e5d0be12164977af254527f56ee96d8719f53f"
},
{
"member": "run02/workshop_sa_folded/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_folded/stdout.jsonl",
"bytes": 194613,
"sha256": "ddf05a2ca36950305090bd5d91ec2a6c617d2eae373c33ad84e9ff4157581c0c"
},
{
"member": "run02/workshop_sa_original/receipt.json",
"bytes": 1126,
"sha256": "651545fe8696abb0b1ef33b606e619e3248c977c525387f1de7b89dd4353b82d"
},
{
"member": "run02/workshop_sa_original/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"member": "run02/workshop_sa_original/stdout.jsonl",
"bytes": 198272,
"sha256": "e30a2a6a30d1522cb2f8e9377e7eb8f0a81d1fe8b5aa18550f78c4829b8cc408"
}
]
}
@@ -0,0 +1,23 @@
# SCC checkpoint final claim and archive review
Reviewed the current results.md and immutable evidence archive for tested source `2426d286483ab0445663221cd6010a3dadb89a97`. Verdict: **no blocking finding for this experimental checkpoint**. This is evidence/claim acceptance, not production Arrange or native usability acceptance.
## Verified facts
- Independently opened the ZIP and checked every member against manifest bytes and SHA256, exact membership and uniqueness, plus ZIP CRC readback (`testzip`). All 168 members pass. Archive: 6,041,259 bytes; SHA256 `fbf40882ed807a1b40db8b3b9b9c846b060db02cbcc60611c18f9620c1fd59c9`.
- Both run receipts bind unchanged before/after inputs, correct source pins, eight successful bounded children with no timeout, and exact captured stdout/stderr sizes/hashes. Both route-control byte streams hash to `9a31a676f23dea2f41daec39497f569d68231fa0fd66e5a1a476be97d5d61ac2`.
- Independently matched **all 14** complete results-table rows against archived Arrange-reset controls and final candidate metrics, including crossings, raw shared length, all three label counts and rounded area ratios. The bipartite, folded, workshop and two-container regressions are disclosed, not hidden behind sparse-case gains.
- Compared all raw input Projects across runs: unchanged. All 13 previously supported complete candidate objects remain exactly equal. The original two-container `Final Rust projection differs from intended node geometry` rejection is retained; run02 supports that case. All 14 emitted repeat and JSON/source roundtrip checks pass. These emitted checks are correctly distinguished from independently retained repeated full Projects, which are not serialized.
- Gate receipts/logs support source 2426d286's 8 example tests, strict Clippy and optimized build (24–26); source 4dd764fa's 5 tests/Clippy/build (21–23); earlier packing tests; and the retained gate20 exit101 `needless_range_loop` failure. All gate input inventories report unchanged. No whole-workspace claim is made.
## Interpretation and limits
The transfer explanation agrees with the source review and independently derived run01 failure: preserve unchanged effective expanded minima only for qualifying position-exact, noncollapsed nodes that would otherwise shrink, then require one exact final projection. This restores the intended 308×446 parents without changing SCC packing/order/gaps. The unchanged 13 candidate objects strengthen this attribution; the newly supported two-container result still has 164 sharing and one label/node collision, so the correction is not presented as a quality improvement.
The quality verdict is proportionate. Sparse coherent SCCs remove the dominant shared corridor, while residual label conflicts, folded retrace, relation-ID-dependent routing and area costs remain. The evidence supports keeping the structural hypothesis and conducting a bounded next experiment; it does not establish engineer traceability, general lane separation, glyph readability or product acceptance. Proposed external-neighbor sibling ordering should preserve the SCC witness and the fixed full-corpus comparison; its benefit remains unverified.
Archive contents include both runs, failed gates, frozen five-case inputs, controls, scripts and independent reviews. Source is identified by commit; binaries are intentionally excluded but their capture hashes remain. Repository-relative build/CLI examples are suitable reproduction entry points after obtaining that source and locked dependencies. Archived supervisor scripts/receipts retain machine-local paths and Windows environment assumptions: they are provenance, not an automatically portable runner. Short observed runtimes are not performance guarantees; the work counter is weighted. Linux, native workflows, command/history integration, dormant-route translation and State-header coverage remain explicitly outside this checkpoint.
Minor optional wording: “failed flat lead-clearance repair” could read “flat lead-clearance repair rejected on readability grounds”; that earlier repair did remove the targeted lead incompatibility. The surrounding linked results and current non-adoption verdict make this nonblocking.
Review method: read-only archive/JSON/log/source-review inspection and offline comparisons. No compiler, router, GUI or test process rerun. No source/archive changes. Publication remains unconfirmed until parent obtains Gitea success and readback.
@@ -0,0 +1,34 @@
# SCC-block placement prototype
Research-only `examples/auto_layout_probe/condensed.rs`. APIs `candidate(&Project, Id)` and `candidate_with_diagnostics(&Project, Id)`; the latter returns `(Project, serde_json::Value)`. No compiler, formatter, engine or GUI run by implementation agent. Parent owns integration and execution.
The implementation freezes actual projected node minima and visual-parent forest. It rejects Scenario and graphs over256stored nodes/1024visible edges. Folded placements are opaque projected leaves; the authoritative parent import preserves their stored expanded size and moves hidden descendants. No semantic parents, edge direction, port anchors or route fields are directly edited by the module.
Process sibling groups bottom-up. Lift each visible endpoint to its immediate child subtree; form directed arcs only from directed edges. Bounded reachability computes exact SCCs of that **quotient graph**, which need not equal global semantic SCCs. Condensation longest-path ranks cannot interleave a component's members. Undirected links influence local spacing and deterministic same-rank proximity, never rank direction. Canonical alias/placement-ID order breaks ties, independent of edge IDs. Within each SCC, deterministic directed DFS successor walk chooses clockwise perimeter order.
For a multi-node SCC, enumerate finite integer perimeter grids with enough slots. Use maximum member dimensions and local internal edge-label gaps; select minimum bounding area among physical aspect ratios≤2, then area/rows/columns ties. If no such grid exists within the bounded enumeration, select closest aspect, then area/rows/columns. This near-square restriction was approved before execution; unconstrained area minimization would produce a strip. Singletons retain their size. Fixed one-pass prior-neighbour ordering plus a canonical same-rank adjacency walk affects component proximity without changing ranks.
Component and rank-cut gaps use relevant core-estimated label bounds plus32, minimum32, rather than one diagram-wide maximum. Each compound encloses its child layout with32horizontal/bottom padding and actual State header (otherwise64) plus32top separation, taking maxima against frozen projected minima. Absolute positions are accumulated through the visual forest at root origin40,40. Work cap20000000charged units, extent100000; no quality-score iteration or clearance repair loop.
Exactly one parent `import_placement` call applies final positions/sizes and authoritative original-to-final route/reset/hidden translation policy. Its final reprojection gate rejects automatic-capacity or container-size divergence rather than repairing indefinitely. The actual final lead diagnostic rejects incompatible mandatory leads explicitly; an empty diagnostic is necessary only, not full-route or readability acceptance. Diagnostics expose parent groups, SCC membership/DFS walk/rank/grid/gap, lifted directed and undirected pairs, component offsets/envelopes and work usage.
Two pure tests cover SCC separation across a one-way bridge and unique nonoverlapping ten-node perimeter slots. They are unexecuted. Repeat stability and meaningful preservation/geometry tests remain parent's run gates. Large local labels may still produce oversized SCCs; quotient cycles and cross-container semantic cycles are heuristic limitations, not equivalent semantic SCC claims. Routing used to obtain label bounds is bounded by existing core machinery but is not included in the prototype's own charged-loop count; this is not a runtime latency guarantee.
## Parent integration addendum
The preceding text is the implementation handoff before execution. Source
ea18adc0 corrects perimeter scoring to use occupied cells, includes single-row
and single-column candidates, and adds a two-node witness. It scores maximum
member-cell envelopes, not an exact aspect guarantee for heterogeneous nodes.
Source4dd764fa fixes a Clippy row-iteration warning; five example tests, strict
Clippy and the release build pass. Run01 supports13 of14 frozen cases.
Source2426d286 changes only the shared example importer and its tests, not SCC
placement. One bounded conditional restoration preserves intended unchanged
effective container minima after children move inward. Three regression tests
cover that failure, expanded/folded identity and inconsistent-plan rejection.
All eight example tests, strict Clippy and optimized build pass. Run02 supports
all14 cases and leaves all13 prior successful candidate objects exactly equal.
Independent quality reviews still reject production adoption. See the final
results, transfer diagnosis, source review v2 and run02 reviews for the complete
evidence and limitations; the early unexecuted status above is historical.

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