Add bounded external placement comparison and preservation adapter

This commit is contained in:
2026-09-24 20:12:01 -07:00
parent ac5d7ef34a
commit 8a2010d8a6
10 changed files with 851 additions and 1 deletions
@@ -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; });
}