Skip to content

layout: revisit AC1.8 scale-invariance term classification during Phase 4 calibration #631

@bpowers

Description

@bpowers

During Phase 1 of the layout-quality-eval plan (commit a039309), the implementer found that the plan's acceptance criterion AC1.8 (scale-invariance) misclassifies which LayoutMetrics terms are exactly scale-free, and corrected the test to match the geometry the renderer actually draws. This needs to be revisited during Phase 4 (calibration) to decide whether the metric definitions or the AC1.8 classification should change.

This is a design-doc-vs-implementation consistency concern, not a code bug -- the implemented behavior is defensible and well-documented. The task is to reconcile the plan's AC1.8 term list with geometric reality and lock in the intended cross-model-comparable semantics.

The discrepancy

docs/implementation-plans/2026-05-22-layout-quality-eval/phase_01.md (AC1.8 SCOPING note, ~line 28) classifies four terms as scale-free / scale-invariant:

  • node_connector_overlap
  • crossings
  • edge_length_cv
  • aspect_penalty

The implementer's analysis (now documented in src/simlin-engine/src/layout/metrics.rs, AC1.8 test comment ~lines 877-906) is that because diagram element boxes are fixed-pixel constants (AUX_RADIUS=9, stock 45x35, etc.) that do NOT scale with coordinates, and connectors are clipped to fixed-radius element boundaries, only crossings (a topological count) is EXACTLY scale-invariant. The other three carry a fixed-pixel additive offset and are only asymptotically scale-invariant (as the scale factor grows large):

  • node_connector_overlap = (length inside a fixed-size box, non-scaling numerator) / (connector length, scaling denominator) -> actually scale-SENSITIVE; it shrinks under up-scaling (like sprawl).
  • edge_length_cv uses affine clipped lengths (s*center_dist - r_from - r_to) -> stddev/mean of affine lengths is only asymptotically invariant (the fixed offset shrinks relative to the scaled spread).
  • aspect_penalty bounding box = union(fixed-size boxes around scaled centers), so width/height are each s*span + fixed_box_size -> the aspect ratio is only asymptotically invariant.

What was changed in Phase 1

The test test_scale_invariance_of_scale_free_terms in src/simlin-engine/src/layout/metrics.rs was corrected to:

  • assert exact invariance ONLY for crossings, and
  • additionally pin node_connector_overlap's documented scale-SENSITIVITY (it strictly decreases under up-scaling) so the scoping is non-vacuous.

The fixture is built with zero node-overlap and zero label-overlap so those scale-sensitive area terms are trivially equal (0) before and after scaling.

Why it matters

  • Doc/implementation consistency: the plan's AC1.8 term list disagrees with the implemented metric. Whichever is canonical, the two should be reconciled so future phases (and reviewers) aren't misled.
  • Calibration correctness: Phase 4 tunes term weights. Whether node_connector_overlap / edge_length_cv / aspect_penalty are treated as scale-invariant or scale-sensitive affects how their weights generalize across models of different absolute coordinate scales.

Component(s) affected

  • src/simlin-engine/src/layout/metrics.rs (the LayoutMetrics terms and the AC1.8 test)
  • docs/implementation-plans/2026-05-22-layout-quality-eval/phase_01.md (the AC1.8 SCOPING note)

Decision to make in Phase 4

Decide whether node_connector_overlap, edge_length_cv, and aspect_penalty should be redefined for true (exact) scale-invariance, OR whether their fixed-pixel-relative sensitivity is the intended cross-model-comparable behavior -- which is exactly what the plan already argues for node_overlap / label_overlap / sprawl. If the latter, update the AC1.8 note and term list to say only crossings is exactly scale-invariant and the rest are intentionally scale-sensitive (or asymptotically invariant) by construction.

How it was discovered

Identified during execution of the layout-quality-eval implementation plan, Phase 1 (commit a039309), while implementing the metric against the actual renderer geometry (the phase's load-bearing invariant: metrics are computed on the same geometry the renderer draws). Surfaced in the executor report and tracked here for the calibration phase.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions