# How Archify Composition Checks Work: Label Clearance and Relationship Crossing Rules Explained

> Understand Archify composition checks label clearance and relationship crossing rules. Learn how these geometric validations ensure diagram readability and semantic correctness.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: deep-dive
- Published: 2026-08-10

---

**Archify composition checks are geometric validations that run after SVG rendering to enforce spacing rules (minimum 4px clearance) and prevent unrelated relationships from crossing.** These checks operate purely on coordinate data, independent of the source model, ensuring diagrams remain readable and semantically correct.

The Archify rendering engine doesn't just draw diagrams—it validates them. After generating the final SVG, the `runCompositionChecks()` function in `geometry.mjs` inspects every spatial relationship between elements. This article explains how **label-route clearance** and **proper crossing** detection work, based on the actual implementation in the `tt-a1i/archify` repository.

## What Are Archify Composition Checks?

Composition checks are **pure-geometry rules** that validate spatial relationships after rendering completes. Unlike model-level validations, these operate on the final coordinate data—`points`, `rects`, and `segments`—produced by the renderer.

Archify implements five composition checks total, with two covered here:

| Check | Code | Purpose |
|-------|------|---------|
| **Proper crossing** | `composition/proper-crossing` | Prevents unrelated relationships from intersecting |
| **Label-route clearance** | `composition/label-route-clearance` | Enforces minimum distance between labels and foreign routes |
| Ambiguous corridor | `composition/ambiguous-corridor` | Maintains 4px separation for parallel merged routes |
| Container-border run | `composition/container-border-run` | Limits how long routes hug frame borders |
| Micro-segment | `composition/micro-segment` | Enforces minimum visible segment lengths |

The **label clearance** and **relationship crossing** checks form the core visual integrity rules for professional-quality diagrams.

## How Label-Route Clearance Detection Works

The label-route clearance check ensures **label bounding boxes never sit too close to relationship lines they don't belong to**. The implementation follows four precise steps:

### 1. Extract Label Rectangles

Every label node converts to an axis-aligned rectangle via `hit.rect`. The dimensions derive directly from the rendered `<text>` element's `x`, `y`, `width`, and `height` attributes.

### 2. Measure Distance to Foreign Routes

For each relationship **not** associated with the label, Archify walks every polyline segment and calls `segmentRectClearance()` in `archify/renderers/shared/geometry.mjs`:

```javascript
// geometry.mjs (line 46) – perpendicular distance calculation
export function segmentRectClearance(segment, rect) {
  const { start, end } = segment;
  // Compute minimal perpendicular distance from segment to rectangle
  // Returns numeric clearance, or null if segment is inside rectangle
}

```

This function calculates the **minimal perpendicular distance** from the line segment to the rectangle boundary.

### 3. Apply Quality Profile Thresholds

Each profile defines a clearance threshold. The **showcase** profile defaults to **4px**, defined in `archify/bin/archify.mjs` at line 187:

```javascript
// archify.mjs – rule configuration for showcase quality
{
  code: 'composition/label-route-clearance',
  threshold: 4,  // pixels
  severity: 'error'
}

```

### 4. Generate Actionable Issues

When clearance falls below threshold, Archify pushes a structured issue object. From `geometry.mjs` around line 826:

```javascript
// geometry.mjs – label clearance violation reporting
if (clearance < threshold) {
  issues.push({
    code: 'composition/label-route-clearance',
    clearance,           // measured: e.g., 2
    threshold,           // required: e.g., 4
    labelRelation,       // the label's parent relationship
    otherRelation,       // the foreign relationship too close
    segmentIndex,        // which segment violated
    rect,                // label bounding box
    message: `[composition/label-route-clearance] ${diagramType} label "${hit.label?.label}" ...`
  });
}

```

The message specifically names the label, offending relationship, segment index, and exact distance—guiding authors to adjust `labelAt`, `labelDx`, `labelDy`, or `labelSegment` properties.

## How Relationship Crossing Detection Works

The **proper crossing** check prevents semantically unrelated relationships from visually intersecting, which could imply false connections.

### Segment Pair Intersection Testing

Archify enumerates all **unrelated relationship pairs** (different `collectionId`s) and tests every segment combination:

```javascript
// geometry.mjs – proper crossing detection (around line 432)
if (segmentIntersectsSegment(aSeg, bSeg)) {
  const point = calculateIntersection(aSeg, bSeg);
  issues.push({
    code: 'composition/proper-crossing',
    point,                    // [x, y] intersection coordinate
    left: leftRelation,        // first relationship
    right: rightRelation,      // second relationship
    message: `[composition/proper-crossing] ${diagramType} ${describe(left)} crosses ${describe(right)} at [${point}]`
  });
}

```

The `segmentIntersectsSegment()` helper performs the core geometric intersection test in `geometry.mjs`.

### Severity by Quality Profile

| Profile | Crossing Severity | Rationale |
|---------|-------------------|-----------|
| **showcase** | Error | Professional diagrams must never have accidental crossings |
| standard | Warning | Acceptable for draft quality |
| minimal | Warning | Lenient for exploration |

This mapping lives in `archify/bin/archify.mjs` alongside the code-to-action configuration at line 184.

## Composition Check Orchestration

All checks flow through a central pipeline. The `runCompositionChecks(diagram, qualityProfile)` function in `geometry.mjs` aggregates results, which `check-render-output.mjs` merges into the final validation receipt (line 154):

```javascript
// check-render-output.mjs – integrating composition results
const composition = runCompositionChecks(diagram, qualityProfile);
const receipt = {
  checks: [...],
  composition: {
    status: composition.issues.length ? 'fail' : 'pass',
    issues: composition.issues,
    metrics: composition.metrics
  }
};

```

The CLI then surfaces remediation hints based on issue codes.

## CLI Validation Example

Run composition checks via the command line:

```bash
$ npx archify validate diagram.json --quality showcase --json

```

Example output with both violations:

```json
{
  "checks": [...],
  "composition": {
    "status": "fail",
    "issues": [
      {
        "code": "composition/label-route-clearance",
        "clearance": 2,
        "threshold": 4,
        "message": "[composition/label-route-clearance] showcase dataflow label \"User\" is 2px from route (requires 4px)..."
      },
      {
        "code": "composition/proper-crossing",
        "point": [120, 45],
        "message": "[composition/proper-crossing] showcase dataflow relationship 'auth' crosses 'cache' at [120,45]"
      }
    ]
  }
}

```

## Why Composition Checks Matter

- **Readability** – Overlapping labels and crossing arrows create visual clutter that obscures diagram meaning
- **Correctness** – A crossing often signals unintended logical relationships in the underlying model
- **Automation** – Deterministic geometry enables consistent enforcement across all diagram types (dataflow, architecture, workflow)

The separation from source model validation means Archify catches **rendering artifacts** that model checks cannot—such as label placement algorithms producing overlaps or route bundling creating accidental intersections.

## Summary

- **Archify composition checks** run post-render on coordinate data, not the source model
- **Label-route clearance** enforces 4px minimum distance between labels and foreign relationship routes via `segmentRectClearance()` in `geometry.mjs`
- **Proper crossing detection** prevents unrelated relationships from intersecting using `segmentIntersectsSegment()`
- **Quality profiles** control severity—showcase treats crossings as errors, other profiles as warnings
- **Issue messages** include precise measurements and property names (`labelAt`, `labelDx`, etc.) for direct remediation
- The orchestration flows through `runCompositionChecks()` → `check-render-output.mjs` → CLI reporting with `archify.mjs` severity mappings

## Frequently Asked Questions

### How do I fix a label-route clearance violation in Archify?

Adjust the label positioning properties on the parent relationship. The issue message specifies which relationship and segment triggered the violation. Modify `labelAt` (segment index), `labelDx` (horizontal offset), `labelDy` (vertical offset), or `labelSegment` to increase distance from the foreign route. The showcase quality profile requires **4px minimum clearance**.

### Why does Archify detect crossings that don't look like intersections in my diagram?

Archify tests **mathematical segment intersection**, not just visual overlap. Rounded line caps, thick strokes, or anti-aliasing may make lines appear separated when their centerlines actually cross. The `point` coordinate in the issue message shows the exact intersection location. Increase `corridorPadding` or adjust route waypoints to separate the lines.

### Where are composition check thresholds configured?

Quality-specific thresholds reside in `archify/bin/archify.mjs` (line 184–190). The showcase profile hardcodes 4px for label-route clearance. Custom profiles can override these values by passing a modified `qualityProfile` object to `runCompositionChecks()`. The `geometry.mjs` file contains the measurement logic but not the threshold values.

### Can I disable specific composition checks?

The CLI does not support disabling individual checks directly. Create a **custom quality profile** with adjusted severity mappings—set `composition/proper-crossing` or `composition/label-route-clearance` to `'ignore'` in your profile configuration. Pass this profile via `--quality ./my-profile.json` when running validations.