perf(layout-bridge): cache footnote convergence to reduce typing latency#3707
perf(layout-bridge): cache footnote convergence to reduce typing latency#3707mattConnHarbour wants to merge 3 commits into
Conversation
Add a cache for footnote reserve convergence to skip the expensive multi-pass loop on subsequent keystrokes. The cache key is the set of footnote IDs (stable across edits), not positions (which shift on every keystroke). On cache hit: - Skip the 4-pass convergence loop (saves ~140ms) - Skip grow/tighten post-processing loops - Skip widow/orphan absorb and preferred reserve trials Cache is invalidated when footnotes are added or removed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Further optimize footnote convergence by skipping the initial Pass 1 (measure + compute plan) when we have a cache hit. Previously we ran Pass 1 before checking the cache, then used cached reserves anyway. Now on cache hit: - Skip Pass 1 entirely - Use cached reserves directly - Do single relayout with cached reserves Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move footnote convergence cache logic into a dedicated class with clear methods: checkHit(), getReserves(), getSeparatorSpacingBefore(), update(), and clear(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 966e25e129
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // Cache hit: skip grow/tighten loops entirely — reserves are already optimal | ||
| if (usedCachedReserves) { | ||
| console.log('[layout] Skipping grow/tighten loops (using cached reserves)'); | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Validate cached footnote reserves before skipping correction
When the same footnote IDs remain but their anchors move to different pages/columns (for example, typing above a footnote or opening another document with the same generated IDs), the cached page-index reserve vector can no longer match finalPlan.reserves. The code recomputes finalPlan after applying the cache, but this early return prevents the existing grow/tighten safety loop from fixing under-reserved or dead-reserved pages, so injectFragments can place footnotes into a page that was not reserved for them and overflow the band. Let the finalPlan vs reservesAppliedToLayout checks run on cache hits, or make the cache key include the page/column assignment and other layout inputs that affect reserves.
Useful? React with 👍 / 👎.
|
📦 Preview published: npm install superdoc@pr-3707 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
📦 Preview published: npm install superdoc@pr-3707 |
Summary
Problem
Typing was slow in documents with footnotes because the footnote reserve convergence loop ran 4 passes per keystroke, each re-paginating the entire document (~30-40ms per pass).
Footnotes create a circular dependency: reserving space at page bottom pushes body text to the next page, which may move footnote references to different pages, requiring re-convergence.
Solution
Added
FootnoteConvergenceCacheclass that caches converged reserves keyed by footnote ID signature:Performance
Test plan
Closes SD-3418
🤖 Generated with Claude Code