Skip to content

perf(mobile): prepare word diffs for visible rows - #9699

Open
t3dotgg wants to merge 3 commits into
mainfrom
t3code/perf-mobile-visible-word-diffs
Open

perf(mobile): prepare word diffs for visible rows#9699
t3dotgg wants to merge 3 commits into
mainfrom
t3code/perf-mobile-visible-word-diffs

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 4, 2026

Copy link
Copy Markdown
Member

Native release hold

Hold this PR for a compatible native release. It changes the iOS and Android review module.

Mobile prepared word highlights for every changed line before showing a large diff. Prepare source rows first, then compute word ranges for visible replacement pairs. Indexing, skipped rows, and word matching yield during long requests. Keep word work independent of syntax highlighting and send ranges through the existing native setter. Android reports source row indexes after file collapse.

Mark rows complete only after native accepts their patch. Retain the last visible range when highlights reset in the same thread and section.

Validation:

  • 49 focused tests, mobile typecheck, and targeted lint passed. Headless React tests cover replaced dispatch frames and scrolled resets.
  • 130 source cases preserve text and coordinates. After visiting all rows, word ranges match the eager implementation.
  • On the original 25-file audit fixture, initial row preparation fell from 294.75 ms to 25.81 ms. The first visible word request took 17.64 ms including yields. Initial row JSON fell from 9.46 MB to 7.33 MB.
  • On 300,008-row fixtures, maximum synchronous work fell from 29.43 ms to 4.24 ms for mostly collapsed rows and from 85.53 ms to 4.05 ms for non-pair rows. Yielding increased the collapsed fixture's total elapsed time.

Measurements used Node 24.20.0. The original fixture used two warmups and six samples. The larger scan checks used one sample each. They exclude native decode and drawing. No local native build, browser, or device testing. Native release and device verification remain required. Existing line-length and coverage rules stay intact.

Refs #9661.

Created with GPT-6 Astra (preview) in Codex.


Note

Medium Risk
Touches iOS/Android review rendering and async patch ordering; incorrect stale-patch handling could show wrong or missing word highlights, but no auth or data-path changes.

Overview
Defers word-level diff highlighting so large reviews no longer compute every deletion/addition pair up front. Row preparation drops embedded wordDiffRanges; a new computeVisibleNativeReviewWordDiffRanges path indexes pairs once (with yield/cancel budgets), matches only the visible window (plus overscan), respects collapsed files, and caches completed pairs.

Streams ranges to native separately from syntax tokens. useNativeReviewDiffHighlighting runs word work in its own effect, sends wordDiffRangesByRowId through the existing token patch bridge (wordDiffRangesPatchJson / setTokensPatchJson), and marks rows complete only after native dispatch via onWordDiffRangesPatchSent. Highlight resets clear native word state but keep the last scroll range within the same thread/section (contentResetKey vs tokensResetKey).

iOS and Android review modules merge patched ranges into drawing state, fall back to row JSON ranges, and report source row indexes in visible-range debug events so JS range requests stay aligned when files are collapsed. Tests add react-test-renderer coverage for delayed patches and scroll/reset behavior.

Reviewed by Cursor Bugbot for commit 166f5fa. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Compute word diffs asynchronously for visible rows only in mobile review diff

  • Moves word-diff pairing and range computation out of synchronous row preparation into a new async module nativeReviewWordDiffs.ts that processes only visible rows plus a bounded overscan, yields to the event loop, and cancels obsolete work
  • Sends computed word ranges to native views (iOS and Android) as row-ID keyed patches through the existing setTokensPatchJson bridge command, with a delivery acknowledgement callback that excludes already-delivered row IDs from future requests
  • Native drawing on both platforms now prefers cached patched ranges over embedded row ranges, falls back to the original embedded ranges when no patch exists, and clears word-range state on token or content resets
  • Adds sourceIndex to parsed DiffRow models so visible-range debug events report original payload row indexes rather than laid-out indexes
  • Risk: prepareFileRows in nativeReviewDiffAdapter.ts no longer mutates rows with computed word ranges; any out-of-tree caller relying on DiffRow containing pre-computed word ranges at construction time will not find them

Macroscope summarized 166f5fa.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.5 KiB +16 B (+0.1%) 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.0 KiB +5 B (+0.1%) 7.3 KiB
Codex Live turn WebSocket wire 6.5 KiB 6.5 KiB +11 B (+0.2%) 7.8 KiB
Codex Live turn WebSocket decoded 57.0 KiB 57.0 KiB 0 B (0.0%) 66.4 KiB
Codex Live turn messages 8 8 0 (0.0%) 21
Claude Total thread wire 13.7 KiB 13.8 KiB +10 B (+0.1%) 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.0 KiB +3 B (+0.0%) 7.3 KiB
Claude Live turn WebSocket wire 6.7 KiB 6.7 KiB +7 B (+0.1%) 7.8 KiB
Claude Live turn WebSocket decoded 59.3 KiB 59.3 KiB 0 B (0.0%) 66.4 KiB
Claude Live turn messages 10 10 0 (0.0%) 21

Baseline: c163d50 · PR result: 166f5fa · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0184829. Configure here.

Comment thread apps/mobile/src/features/review/useNativeReviewDiffHighlighting.ts
@macroscopeapp

macroscopeapp Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes the production mobile diff-rendering pipeline from eager all-row word matching to asynchronous, visibility-scoped computation with new JS-to-native patch state on both Android and iOS. The cross-platform lifecycle, caching, cancellation, and delayed rendering behavior make this more than a small isolated performance tweak.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg t3dotgg mentioned this pull request Sep 4, 2026
66 tasks
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant