Skip to content

fix(agent-map): hold orchestration chevrons at a fixed pitch - #14256

Open
brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/agent-map-chevron-pitch
Open

fix(agent-map): hold orchestration chevrons at a fixed pitch#14256
brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/agent-map-chevron-pitch

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

ELI5

The little > > > > arrows that run between agents on the Agent Map were spread out to fill whatever gap they had to cross. Two agents close together got tight arrows; two far apart got the same number of arrows stretched thin. Now every arrow sits exactly 8px from the next one, no matter how far apart the agents are.

What Changed

agent-map-lineage-chevron-path.ts:

  • Fixed pitch. CHEVRON_SPACING = 8 only ever chose how many chevrons to draw — placement then divided the edge evenly (totalLength * (index + 1) / (count + 1)), so the gap tracked the edge length. Chevrons now step at a literal 8px pitch, with the run centered on the trimmed segment so it never overhangs either node.
  • MAX_CHEVRONS_PER_PATH 32 → 256. With fixed pitch the cap decides how far the run reaches, not just how dense it is. At 32 it covered only 248px, so every longer link would have drawn a short chevron cluster stranded mid-edge with bare gaps at both ends. 256 covers ~2048px — past any real in-project link (adjacent worktree rings sit ≥152 units apart; a large project tops out around 1400) — and stays as a runaway guard on path-string size.
  • Memoized the generated path per endpoint coordinates, LRU-bounded at 512 entries.

Why

The pitch bug is visible in the app: the long cross-worktree links read as sparse dashes while short intra-ring links read as a dense dotted line, so the same relationship looked like two different kinds of edge depending on where packing happened to place the rings.

The memo is here because fixed pitch makes edge length drive the chevron count, which raises the d payload on long links (a 1200px edge goes 1.2 KB → 5.0 KB). That lands on a path with no caching at all: AgentMapScene and AgentMapWorktreeRingNode both call the generator inline inside .map(), and the scene fully re-renders on every zoom frame and on 4Hz snapshot refreshes (refreshAgentMapMetadata rebuilds every node object, so layout identity always changes and no ring node bails out). That was ~150 KB of string churn per frame during a zoom gesture before this change.

Node positions are in world space, so zooming changes no endpoint coordinate — the cache hits ~100% during zoom gestures and across metadata-only refreshes, and only misses during enter/exit motion, when nodes genuinely move. Panning was already free (AgentMapScene is memo'd and only center changes).

Measured on the real module, 60 edges per render pass:

edge length chevrons d per edge build, uncached build, cached
400px 45 1.5 KB 0.54 ms 0.18 ms
1200px 145 5.0 KB 1.89 ms 0.06 ms
4000px (cap) 256 9.5 KB 2.98 ms 0.02 ms

Linked Issue

N/A — reported directly from the running app, no tracking issue.

Visual Proof

Same 42-agent / 41-edge fixture in both, published over the real dashboard:publishSnapshot relay into the pop-out map. Measured from the rendered DOM (tip-to-tip distance on every [data-agent-map-lineage-link]):

edges span range chevron gap range
Before 41 6 → 790 units 6.0 → 25.47 (4.2× variation)
After 41 8 → 832 units 7.999 → 8.001

The longest edge before drew its capped 32 chevrons at a 25.47 pitch; after, it draws 105 at 8.

Before

before.png

After

after.png

Close-up of the same region — watch the long links from orchestrator down to catalog-identity, folder-note, and unified-gate against the short links inside each ring:

Before After
before-crop.png after-crop.png

Testing

  • pnpm typecheck — clean
  • oxlint + audit:code-quality:native — clean
  • vitest run src/renderer/src/components/dashboard-popout — 31 files, 268 tests pass
  • Electron dev build over CDP on macOS: isolated profile, map rendered in the pop-out, before/after captured by reverting the algorithm in the working tree so both states ran against identical fixture data.

New tests in agent-map-lineage-chevron-path.test.ts:

  • tip-to-tip delta is exactly 8 at distances 60 / 200 / 900
  • cap test updated 32 → 256
  • cache serves an unmoved edge without a second insert (proves a hit, not just equal output)
  • cache stays bounded at 512 as edges churn

Platforms: exercised on macOS. Pure renderer geometry + an in-memory Map, no platform, path, SSH, or remote-wire surface touched.

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

Review

  • Security — no new input handling; the cache key is built from numbers already in the layout.
  • Cross-platform — renderer-only geometry, no paths, shortcuts, or shell.
  • Remote SSH / mobile — no wire format, RPC, or published-content change; the map is desktop renderer UI.
  • Backwards compatibility — no persisted state, no settings, no schema.
  • Performance — the point of half the diff; see the table above. Worst-case cache retention is 512 entries (~0.75 MB at typical path sizes, capped per entry by MAX_CHEVRONS_PER_PATH).

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

CHEVRON_SPACING only chose how many chevrons to draw; placement then divided
the edge evenly, so the pitch grew with the distance between agents and, past
the 32-chevron cap, grew without bound. Step at a literal 8px pitch instead,
centering the run so it never overhangs either node.

Fixed pitch makes length drive the chevron count, so cap coverage now decides
how far the run reaches: at 32 it spanned only 248px and every longer link
would have shown a chevron cluster stranded mid-edge. Raise it to 256 (~2048px,
past any real in-project link) and memoize the generated path per endpoint
coordinates, since the scene rebuilds every path string on each zoom frame and
on 4Hz snapshot refreshes while world positions stay put.
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 21929721-ee6a-499a-80b4-fc28e8a8fc5d

📥 Commits

Reviewing files that changed from the base of the PR and between 3ab8b6a and 67ebdd9.

📒 Files selected for processing (2)
  • src/renderer/src/components/dashboard-popout/agent-map-lineage-chevron-path.test.ts
  • src/renderer/src/components/dashboard-popout/agent-map-lineage-chevron-path.ts

📝 Walkthrough

Walkthrough

The lineage path generator now places chevrons at fixed 8-unit intervals centered along each path. The per-path limit increased from 32 to 256 chevrons. Direct lineage paths now use a 512-entry LRU cache keyed by node coordinates and radii. The module exports a cache-size inspection function. Tests cover spacing, cache reuse, and cache bounds during edge churn.

Mergeability Score: ⚪ Minimal · up to 67ebd

This change standardizes Agent Map chevron spacing and caches generated paths without changing persisted data or external interfaces; no actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fixed-pitch chevron placement change for the Agent Map.
Description check ✅ Passed The description covers the change, rationale, visual proof, testing, performance, compatibility review, and checklist; only the required linked issue is absent.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

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.

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