Skip to content

[Bug]: Auto-routing infers left/right for a hub above an offset spoke #376

Description

@drewdog88

Archify version or commit

2.17.0-dev.1 (10722002bb8777ecb639d93c49586fae4adf3ae4)

Installation method

Git clone of https://github.com/tt-a1i/archify

Diagram type

Architecture

Exact command

node archify/bin/archify.mjs deliver architecture hub-spoke.architecture.json /tmp/hub-spoke.html --quality standard --json

Minimal redacted JSON reproduction

{
  "schema_version": 1,
  "diagram_type": "architecture",
  "meta": {
    "title": "Hub above an offset spoke",
    "output": "hub-spoke.html",
    "quality_profile": "standard",
    "viewBox": [640, 360]
  },
  "components": [
    { "id": "hub", "type": "cloud", "label": "Hub", "pos": [200, 40], "size": [176, 52] },
    { "id": "spoke", "type": "cloud", "label": "Spoke", "pos": [40, 240], "size": [168, 52] }
  ],
  "connections": [
    { "id": "hub-spoke", "from": "hub", "to": "spoke" }
  ]
}

Hub center x is 288; spoke center x is 124. defaultFromSide therefore returns "left" even though the dominant gap is vertical.

Expected behavior

Automatic routing should leave the hub from the bottom and enter the spoke from the top (dominant axis), or it should infer sides from the path it actually drew. deliver should succeed without authored fromSide/toSide.

Suggested direction: make defaultFromSide / defaultToSide pick the axis with the larger center delta so hub-and-spoke above a row works. A follow-up: edge-through-node supportedFixes should include a concrete via candidate.

Actual behavior

Architecture auto-routing infers fromSide/toSide from horizontal center order first. A hub sitting above an offset spoke is therefore treated as “leave from the left / enter from the right.” The automatic router then draws a vertical dogleg, and Clean Flow rejects the path it just produced (clean-flow/endpoint-side-direction, sideOrigin: "inferred").

The suggested fix in the diagnostic is “keep automatic routing so the renderer can use a side-aware bridge,” but this JSON already uses automatic routing (no fromSide, toSide, route, or via).

This shows up on ordinary hub-and-spoke fabric (one gateway above a row of peers). Explicit fromSide: "bottom" / toSide: "top" plus a single-row layout is a workaround; the auto path should not fail.

Related: when a lower spoke sits in the same column as an unrelated node, the same inference also yields clean-flow/edge-through-node with no concrete via in supportedFixes.

deliver fails at stage render. Auto-router draws a vertical first segment [200, 66] -> [200, 166] and then reports that this does not honor inferred fromSide: "left".

Validation receipt or exact error

{
  "ok": false,
  "command": "deliver",
  "stage": "render",
  "type": "architecture",
  "diagnostics": [
    {
      "code": "clean-flow/endpoint-side-direction",
      "severity": "error",
      "evidence": {
        "endpoint": "source",
        "authoredField": "fromSide",
        "sideOrigin": "inferred",
        "side": "left",
        "segmentIndex": 0,
        "from": [200, 66],
        "to": [200, 166],
        "expectedAxis": "horizontal",
        "expectedDirection": "leftward"
      },
      "supportedFixes": [
        "keep automatic routing so the renderer can use a side-aware bridge, or set truthful fromSide/toSide with perpendicular via segments"
      ]
    },
    {
      "code": "clean-flow/endpoint-side-direction",
      "severity": "error",
      "evidence": {
        "endpoint": "target",
        "authoredField": "toSide",
        "sideOrigin": "inferred",
        "side": "right",
        "segmentIndex": 2,
        "from": [208, 166],
        "to": [208, 266],
        "expectedAxis": "horizontal",
        "expectedDirection": "leftward from the right"
      }
    }
  ]
}

Workaround

{ "id": "hub-spoke", "from": "hub", "to": "spoke", "fromSide": "bottom", "toSide": "top" }

That delivers. Auto mode should not require it for this geometry.

Environment

macOS, Node.js 26.7.0, Cursor. No private topology in this reproduction.

Final checks

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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