Skip to content

fix(web): don't pin actor to FIRST when another actor feeds it#129

Merged
naorsabag merged 3 commits into
masterfrom
fix/actor-pin-collision
May 11, 2026
Merged

fix(web): don't pin actor to FIRST when another actor feeds it#129
naorsabag merged 3 commits into
masterfrom
fix/actor-pin-collision

Conversation

@naorsabag
Copy link
Copy Markdown
Owner

@naorsabag naorsabag commented May 11, 2026

You spotted this — flow `NdFjXxlxv717` (claude-sandbox step 5) had all nodes crushed together because ELK was crashing and the renderer fell back to `computeFallbackPositions` (tighter `FALLBACK_COLUMN_GAP=220` vs ELK's `200+80`).

Root cause

ELK threw:

```
org.eclipse.elk.core.UnsupportedConfigurationException: Node
'openhop-flow.user' has its layer constraint set to FIRST, but has
at least one incoming edge that does not come from a FIRST_SEPARATE
node.
```

The actor-pin from #99 was unconditional. The sandbox flow has two `type: actor` nodes (`user` and `agent-cfg`) with `user → agent-cfg` between them. Both got pinned to layer 0; ELK refuses intra-layer FIRST→FIRST edges → crash → silent fallback to the tight grid layout.

Fix

Tighten the pin predicate: skip `layerConstraint=FIRST` only when the actor is fed by another actor. The common case where an actor is the final response target (e.g. `user ← api` in orion-main) still pins correctly because the response edge's source is an endpoint/service, not an actor.

Verified

  • `examples/order-flow` (1 actor, response loop) — `user` still leftmost
  • `claude-sandbox` flow `NdFjXxlxv717` (2 actors connected) — ELK no longer crashes, gaps back to 200/80 px
  • `v0.1.0` flow `eIxRYAM39kwT` (orion-main) — `user` still leftmost at x=40

Test plan

  • `npm test -w @openhop/web` (42/42)
  • Refresh the sandbox flow on Pages — spacing should look like the other flows

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Updated landing page with enhanced feature descriptions and platform support details
    • Improved AI client skill badge styling with colored indicators
    • Revised quickstart timeline to 30 seconds
    • Updated installation link references
  • Improvements

    • Optimized flow visualization layout algorithm for better node positioning

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Warning

Rate limit exceeded

@naorsabag has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 47 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6bc2e19a-1b98-4950-86c9-7063e1efa423

📥 Commits

Reviewing files that changed from the base of the PR and between f932f30 and 027f55c.

📒 Files selected for processing (1)
  • packages/web/src/lib/flow-layout.ts

Walkthrough

This PR contains two independent changes: README landing page marketing updates including a refreshed hero tagline, colored skill badges, and quickstart timing adjustment, alongside a refinement to the ELK graph layout algorithm that conditionally pins actor nodes to the leftmost layer only when they lack incoming edges from other actors.

Changes

README Marketing Updates

Layer / File(s) Summary
Hero Tagline and Skill Badges
README.md
Hero subtitle is rewritten to describe YAML-driven animated agent data flows and comparative tools; AI-client skill badges for Claude Code, Cursor, and Codex are restyled with colored checkmarks.
Quickstart Section and Link Anchor
README.md
Quickstart section header is updated from "Try it in 60 seconds" to "Try it in 30 seconds"; the NOTE link anchor is corrected from #install to #install-options.

Conditional Actor Node Pinning

Layer / File(s) Summary
Incoming Edge Precomputation
packages/web/src/lib/flow-layout.ts
buildElkGraph now precomputes a set of target node IDs that receive incoming edges from actor nodes, enabling conditional pinning logic.
Conditional Actor Pinning
packages/web/src/lib/flow-layout.ts
Actor nodes are pinned to ELK's FIRST layer constraint only if they do not receive incoming edges from other actor nodes, replacing unconditional actor pinning.

Sequence Diagram(s)

No sequence diagram is generated for this PR, as the changes consist of documentation updates and a single conditional logic refinement without multi-component interaction flows or complex control flow sequences.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • naorsabag/openhop#125: Both PRs contain nearly identical README marketing updates including hero tagline rewrites, quickstart timing changes, and installation anchor corrections.
  • naorsabag/openhop#99: Both PRs modify actor-node pinning in buildElkGraph; this PR adds conditional pinning based on incoming edges, while the earlier PR introduced unconditional actor pinning.
  • naorsabag/openhop#90: Both PRs modify the buildElkGraph function in flow-layout.ts; this PR refines actor-node pinning while the earlier PR added ELK spacing options for back-edge corridors.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main fix in the changeset: preventing actor nodes from being pinned to ELK's FIRST layer when they receive incoming edges from other actor nodes, which resolves the UnsupportedConfigurationException.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/actor-pin-collision

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web/src/lib/flow-layout.ts`:
- Around line 868-871: The loop over topology.displayEdges incorrectly treats
actor self-loops as incoming-from-another-actor; update the conditional inside
the for (const e of topology.displayEdges) block to also check that e.source !==
e.target before adding to incomingFromActor (i.e., only add e.target when
topology.nodeSnapshots.get(e.source)?.nodeType === 'actor' AND e.source !==
e.target), so standalone/self-loop actors are not considered incoming from
another actor.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d5a26904-8ed9-44ad-86c3-68f3ae121015

📥 Commits

Reviewing files that changed from the base of the PR and between 757760d and f932f30.

📒 Files selected for processing (2)
  • README.md
  • packages/web/src/lib/flow-layout.ts

Comment thread packages/web/src/lib/flow-layout.ts
Flows with two actors connected to each other (e.g. user → agent-cfg,
both type=actor) crashed ELK with:

  org.eclipse.elk.core.UnsupportedConfigurationException: Node
  'openhop-flow.user' has its layer constraint set to FIRST, but has
  at least one incoming edge that does not come from a FIRST_SEPARATE
  node.

ELK rejects intra-layer FIRST→FIRST edges. The actor-pin from #99 was
unconditional: every type=actor node got layerConstraint=FIRST. When
two actors connect, both land in layer 0 and ELK refuses to lay it
out. useFlowGraphLayout silently catches and falls back to
computeFallbackPositions, which uses tighter FALLBACK_COLUMN_GAP=220
vs ELK's 200+80 — the visible result was "all the nodes are too close
together" on the affected flows.

Tighten the pin predicate: skip the FIRST constraint only when the
actor is fed by ANOTHER actor. The common case where an actor is the
final response target (e.g. user ← api in orion-main) still pins
correctly because the response edge's source is an endpoint/service,
not an actor — so user stays leftmost.

Tested against:
- examples/order-flow (1 actor, response loop) — user is leftmost ✓
- claude-sandbox flow NdFjXxlxv717 (2 actors connected) — ELK
  no longer crashes, gaps are 200/80 px as expected ✓

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@naorsabag naorsabag force-pushed the fix/actor-pin-collision branch from f932f30 to 98376ef Compare May 11, 2026 10:23
naorsabag and others added 2 commits May 11, 2026 10:28
CodeRabbit on #129: an actor self-loop (source === target) was
incorrectly treated as 'fed by another actor', which would unpin a
standalone actor that happens to have a self-loop step. Self-loops
don't introduce a second FIRST-pinned node, so they can't trigger
the ELK FIRST-FIRST intra-layer error this guard exists to prevent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@naorsabag naorsabag merged commit 39910a9 into master May 11, 2026
8 checks passed
@naorsabag naorsabag deleted the fix/actor-pin-collision branch May 15, 2026 16:00
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