Skip to content

feat(geometry): suggest a verified via elbow for clean-flow routing diagnostics - #308

Open
julianwirawan-hash wants to merge 1 commit into
tt-a1i:mainfrom
julianwirawan-hash:suggest-via-for-clean-flow-diagnostics
Open

feat(geometry): suggest a verified via elbow for clean-flow routing diagnostics#308
julianwirawan-hash wants to merge 1 commit into
tt-a1i:mainfrom
julianwirawan-hash:suggest-via-for-clean-flow-diagnostics

Conversation

@julianwirawan-hash

@julianwirawan-hash julianwirawan-hash commented Sep 4, 2026

Copy link
Copy Markdown

Problem and value

clean-flow/edge-through-node (an edge crossing an unrelated node) and clean-flow/endpoint-side-direction (a route not leaving/entering perpendicular to its authored side) only ever offer generic prose as supportedFixes — e.g. "adjust fromSide/toSide, set route/via or channel coordinates, or move the obstacle." Solving a correct 2-point via elbow for a cross-lane or reverse-flow edge by hand is a well-known, mechanical recipe (leave/enter perpendicular to the authored sides, one shared coordinate strictly between the two lanes) — but it had to be hand-solved and hand-verified per edge, every time, with no help from the tool beyond the generic hint. No existing issue link — found this authoring dense lifecycle diagrams with cross-lane transitions.

Scoped narrower than a full fix on purpose: this does not address arrow-vs-arrow crossings (composition/proper-crossing / composition/ambiguous-corridor) — only an edge's relationship to nodes, not to other edges. It's also not auto-layout (see Roadmap's "Not planned" — auto-layout is explicitly declined): it only computes a repair for an already-diagnosed violation on an already-authored edge, the same category as the existing labelAt suggestion for layout/constraint, not a general positioning engine.

Scope

  • What changed: added suggestClearingVia() to renderers/shared/geometry.mjs — given the two endpoint rects, fromSide/toSide, and the obstacle set, it samples candidate midpoints for the standard 2-point elbow and returns the first one whose three segments are verified clear of every obstacle (reusing segmentIntersectsRect) and that honors both endpoint-side direction contracts (via routeHonorsEndpointSides). Wired into cleanFlowProblems (active for every renderer, since obstacles was already required there) and into cleanEndpointSideProblems via a new optional obstacles parameter, enabled for the lifecycle renderer's transitions.
  • What deliberately did not change: the other 4 renderers' cleanEndpointSideProblems call sites still don't pass obstacles (same one-line change as lifecycle's — left out of this PR to keep it reviewable and scoped to where I could verify the real-world benefit; happy to extend here or in a follow-up, maintainer's call). No change to composition/proper-crossing/ambiguous-corridor. No auto-layout, no general routing engine.
  • No unrelated changes: confirmed — diff is limited to renderers/shared/geometry.mjs, renderers/lifecycle/render-lifecycle.mjs, and test/geometry.test.mjs.

Stability impact

  • Compatibility and migration risk: cleanFlowProblems's signature is unchanged; behavior only changes (message/evidence content) when a verified via is actually found, otherwise falls back to the exact previous generic hint. cleanEndpointSideProblems gains one new optional parameter (obstacles, default []); omitting it keeps today's behavior byte-for-byte, confirmed by a dedicated backward-compatibility test.
  • Renderer, validator, package, or generated-artifact risk: touches a function shared by all 5 renderers' validators (cleanFlowProblems), so I specifically re-ran the architecture and workflow renderers' own test suites (see below) rather than only the new tests.
  • Failure behavior and rollback path: suggestClearingVia returns null (not a guess) whenever it can't verify a candidate — including a real degenerate case I found and fixed during testing (below) — so a failure mode here is "no suggestion," never a wrong one.

Tests run

From archify/:

  • node --test test/geometry.test.mjs — 60/60 pass (7 new tests: suggestClearingVia directly against a real obstacle — verified via segmentIntersectsRect/routeHonorsEndpointSides on the returned points, not a hardcoded expected coordinate; an unsolvable case correctly returning null; a declined mixed-side-combination case; both diagnostics' new message/evidence output; the backward-compatible no-obstacles fallback).
  • node --test test/repair-receipt.test.mjs test/workflow-compiler.test.mjs — 97/97 pass. One existing assertion in repair-receipt.test.mjs needed a one-line update: this change legitimately improved that test's own real fixture's diagnostic (a verified via is now suggested instead of the old generic text), so the assertion now accepts either form.
  • node --test test/architecture-delta.test.mjs test/sequence-column-fit.test.mjs — 24/24 pass.
  • npm test (full suite): could not complete — hangs indefinitely in my sandboxed environment (near-zero CPU for 1.5+ hours; confirmed via process inspection, not legitimate progress). Reproduces identically on unpatched main, so this predates and is unrelated to this change. Every targeted file above runs and completes normally and cleanly.

A real bug caught during testing: an early version of suggestClearingVia could return a degenerate via (two identical points) when source and target anchors shared the same row (horizontal elbow) or column (vertical elbow) — found by running the patch against repair-receipt.test.mjs's own real fixture, not by inspection. Fixed with an explicit guard (Math.abs(start[crossIndex] - end[crossIndex]) < 1) return null), commented in place with the derivation.

Visual evidence

Not applicable — diagnostic message/evidence content only; no renderer output, SVG, or viewer change.

Generated artifacts

  • archify.zip: left unchanged. scripts/build-zip.sh requires Node 22 exactly for canonical byte-identical output; my environment runs Node 24.19.0, so rebuilding here would produce non-canonical bytes. Happy to rebuild if useful, or a maintainer can on merge.
  • No Gallery/README/guide regeneration needed.

Checklist

  • I used a minimal focused change and preserved existing typed JSON behavior unless the issue requires a contract change.
  • I ran the relevant targeted tests and npm test in archify/. — targeted tests (geometry, repair-receipt, workflow-compiler, architecture-delta, sequence-column-fit) all pass; npm test's full suite hangs in my environment (pre-existing, see above).
  • I added or updated a regression test for behavioral changes.
  • I checked generated artifacts and package freshness when their sources changed. — checked; archify.zip needs a Node-22 rebuild I can't produce correctly here.
  • I removed secrets, private repository content, and customer data from fixtures and screenshots.

…iagnostics

clean-flow/edge-through-node and clean-flow/endpoint-side-direction only
ever offered generic prose ("adjust fromSide/toSide, set route/via or
channel coordinates...") even though authoring a correct 2-point via
elbow for a cross-lane or reverse-flow edge is a well-known, mechanical
recipe: leave the source anchor and enter the target anchor
perpendicular to their sides, with one shared coordinate strictly
between the two lanes. In practice this recipe was hand-applied and
hand-verified per edge, per diagram, every time.

Add suggestClearingVia(): given the two endpoint rects, their
fromSide/toSide, and the obstacle set, it samples candidate midpoints
for that elbow and returns the first one whose three segments are
verified clear of every obstacle (via the same segmentIntersectsRect
primitive the diagnostics themselves use) and that honors both
endpoint-side direction contracts (via routeHonorsEndpointSides).
Returns null -- not a guess -- when the two sides aren't both
vertical or both horizontal, when source and target share the
elbow's cross-axis coordinate (would collapse to a degenerate
zero-length via), or when no sampled midpoint clears every obstacle.

Wired into cleanFlowProblems (all renderers, since obstacles was
already a required parameter there) and into cleanEndpointSideProblems
via a new optional "obstacles" parameter (backward compatible --
existing callers that don't pass it keep today's generic-hint
behavior unchanged). Enabled the endpoint-side-direction suggestion
specifically for the lifecycle renderer's transitions, since that's
where this diagnostic is most commonly hit in cross-lane/reverse-flow
diagrams.

Testing: added 7 tests to geometry.test.mjs covering suggestClearingVia
directly (a genuine obstacle it routes around, an unsolvable case that
correctly returns null rather than guessing, and a declined
mixed-side-combination case) plus both diagnostic functions' new
supportedFixes/evidence.suggestedVia output and backward-compatible
fallback. Caught and fixed a real bug during testing: an early version
could suggest a degenerate via (two identical points) when source and
target shared the same cross-axis coordinate -- now explicitly guarded
against.

Verified no regression in every other test file that exercises these
shared functions: repair-receipt.test.mjs + workflow-compiler.test.mjs
(97/97, covers the architecture and workflow renderers' use of the
same functions -- including a real fixture where this change legitimately
improved an existing diagnostic's supportedFixes text, requiring a
one-line assertion update to match), architecture-delta.test.mjs +
sequence-column-fit.test.mjs (24/24). Note: running the full suite as
one "node --test test/*.mjs" glob hangs indefinitely in my sandboxed
environment (unrelated to this change -- reproduces the same way on
unpatched main, likely the same live-server-lifecycle issue behind the
pre-existing 'preview runs from an installed skill' flake); every
targeted file run above completes normally and cleanly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant