Skip to content

perf: replace .move(edge: .bottom) transitions with .opacity in LazyVStack to fix motionVectors hang (LUM-795)#24375

Merged
ashleeradka merged 2 commits into
mainfrom
devin/1775673094-lum-795-remove-move-edge-transitions
Apr 8, 2026
Merged

perf: replace .move(edge: .bottom) transitions with .opacity in LazyVStack to fix motionVectors hang (LUM-795)#24375
ashleeradka merged 2 commits into
mainfrom
devin/1775673094-lum-795-remove-move-edge-transitions

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 8, 2026

Replaces .transition(.opacity.combined(with: .move(edge: .bottom))) with .transition(.opacity) on 4 items inside the LazyVStack in MessageListContentView.swift. The .move(edge: .bottom) component forces SwiftUI to compute the total content height of the LazyVStack during motionVectorsmeasureEstimates, iterating every ForEach child and defeating lazy loading — causing 100+ second main-thread hangs. .opacity only needs the view's own frame, so it's safe inside lazy containers. This is a follow-up to #24321 (LUM-740), which was necessary but insufficient.

Also adds a permanent anti-pattern rule to clients/macos/AGENTS.md and an inline warning comment above the LazyVStack body to prevent reintroduction by future features copying old patterns.


Review & Testing Checklist for Human

  • Build in Xcode and trigger the thinking indicator, compacting indicator, orphan subagent row, and streaming-without-text indicator — verify the fade-in/fade-out animation looks acceptable without the slide-up component
  • With a long conversation (many messages), verify the hang no longer reproduces when these indicators appear/disappear
  • Confirm no other .move(edge:) transitions exist inside the LazyVStack body (the other .move(edge:) usages in the chat area are all in overlays outside the LazyVStack and are unaffected)

Notes

  • CI skips macOS builds, so this can only be verified locally in Xcode
  • The only behavioral change is visual: indicators now fade in/out instead of sliding up + fading. No logic, layout, or structural changes
  • Other .move(edge:) transitions in the codebase (ChatView overlays, ComposerView, error toasts, etc.) are not inside a LazyVStack and don't trigger the measurement issue — they are intentionally left unchanged
  • The AGENTS.md rule references WWDC23: Demystify SwiftUI performance as the authoritative source

Link to Devin session: https://app.devin.ai/sessions/d11994a0494e456ea259a789e3b41f6a
Requested by: @ashleeradka


Open with Devin

…Stack to fix motionVectors hang (LUM-795)

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

…line warning

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

@ashleeradka ashleeradka merged commit 9045ca7 into main Apr 8, 2026
6 checks passed
@ashleeradka ashleeradka deleted the devin/1775673094-lum-795-remove-move-edge-transitions branch April 8, 2026 19:07
noanflaherty pushed a commit that referenced this pull request Apr 8, 2026
…Stack to fix motionVectors hang (LUM-795) (#24375)

* perf: replace .move(edge: .bottom) transitions with .opacity in LazyVStack to fix motionVectors hang (LUM-795)

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>

* docs: add LazyVStack transition anti-pattern rule to AGENTS.md and inline warning

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ashlee@vellum.ai <ashlee@vellum.ai>
Jasonnnz pushed a commit that referenced this pull request Apr 10, 2026
Adds CI-enforced guard tests that scan Swift source files for three known
LazyVStack performance anti-patterns:

1. FlexFrameLayout (.frame(maxWidth:) / .frame(maxHeight:)) in cell hierarchy
2. motionVectors transitions (.transition(.move(edge:))) in cell hierarchy
3. withAnimation in scroll handlers (motionVectors cascade)

Prevents regression of fixes from PRs #24321, #24375, #24411, #24446,
#24530, #24570, #24589.

Part of #24613.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Jasonnnz added a commit that referenced this pull request Apr 10, 2026
* test: add SwiftUI performance guard tests for LazyVStack anti-patterns

Adds CI-enforced guard tests that scan Swift source files for three known
LazyVStack performance anti-patterns:

1. FlexFrameLayout (.frame(maxWidth:) / .frame(maxHeight:)) in cell hierarchy
2. motionVectors transitions (.transition(.move(edge:))) in cell hierarchy
3. withAnimation in scroll handlers (motionVectors cascade)

Prevents regression of fixes from PRs #24321, #24375, #24411, #24446,
#24530, #24570, #24589.

Part of #24613.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add missing cell files to LAZY_VSTACK_CELL_FILES and remove PR references

Adds the 10 allowlisted file basenames to the cell hierarchy list so the
allowlist is actually consulted. Removes historical PR numbers from the
file header comment per AGENTS.md guidance.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: use grep -E for portable ERE alternation in FlexFrame guard

BSD grep (macOS default) doesn't support \| in BRE mode. Switch to
grep -E with | for alternation so the guard works for local dev too.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add SubagentEventsReader to cell files and escape dots in transition grep

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Vellum Assistant <assistant@vellum.ai>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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