mirror of
https://github.com/stablyai/orca.git
synced 2026-09-28 08:02:43 +00:00
fix(diffs): start the restore ceiling at view attach, not component mount
Two P1s from adversarial review (Opus), both introduced by the previous commit. The ceiling was armed in the mount-time layout effect, but the deadline can only be extended at attach while `now < ceiling`. A large or remote diff whose first postRender lands after the ceiling had already elapsed got no window at all, so the restore never ran once -- scroll, selection and setDeletedTextSelectionActive were silently dropped. This repo's own spec allows 20s for the first diff line to appear, so renders past a mount-anchored 15s ceiling are expected. Arm the ceiling at first attach instead, and clamp every deadline re-arm to it. The self-heal also cleared `loadedIndices` unconditionally. requestSectionReload already clears it when it proceeds and refuses while the row is dirty -- which is exactly the state that triggers the skip -- so the only observable effect was to strand the index unscheduled, making the next virtualizer scroll-in refetch a row the user is typing in, over git, on SSH.
This commit is contained in:
+4
-3
@@ -161,9 +161,10 @@ export function useCombinedDiffSectionLoader({
|
||||
storedContent.modifiedContent === liveDraft &&
|
||||
storedContent.originalContent === liveSection?.originalContent
|
||||
if (liveDraft !== draftAtFetchStart && !payloadMatchesLive) {
|
||||
// Why: this index is already marked loaded, so drop that mark and re-drive the fetch —
|
||||
// otherwise a rejected payload pins the section stale with no path back on its own.
|
||||
loadedIndicesRef.current.delete(index)
|
||||
// Why: re-drive the fetch so a rejected payload does not pin the section stale. Do not
|
||||
// clear `loadedIndices` here — requestSectionReload clears it itself when it proceeds,
|
||||
// and refuses while the row is dirty. Clearing unconditionally would strand the index
|
||||
// unscheduled, making the next virtualizer scroll-in refetch a row being typed in.
|
||||
requestSectionReloadRef.current(index)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -109,13 +109,13 @@ export function usePierreDiffNativeView(
|
||||
})
|
||||
}, [editorRef])
|
||||
useLayoutEffect(() => {
|
||||
// Why: no window is granted here. The ceiling starts at the first view attach, not at
|
||||
// component mount — a large or remote diff can attach many seconds later, and a window
|
||||
// measured from mount would already be spent before the view ever exists.
|
||||
const now = Date.now()
|
||||
// Arm once: the ceiling bounds this restore, not each mount. Re-arming per mount (or per
|
||||
// activeGroupId change) would let an unmount/mount cycle extend it forever.
|
||||
if (ceiling.current === 0) {
|
||||
ceiling.current = now + RESTORE_CEILING_MS
|
||||
if (ceiling.current !== 0 && now < ceiling.current) {
|
||||
deadline.current = Math.min(now + RESTORE_DEADLINE_MS, ceiling.current)
|
||||
}
|
||||
deadline.current = now + RESTORE_DEADLINE_MS
|
||||
schedule()
|
||||
}, [activeGroupId, schedule])
|
||||
useLayoutEffect(() => {
|
||||
@@ -193,9 +193,13 @@ export function usePierreDiffNativeView(
|
||||
}
|
||||
{
|
||||
view.current = { host, instance }
|
||||
// Extend while a restore is still pending, but never past the ceiling, and never re-arm
|
||||
// the ceiling here: FileDiff emits 'mount' on every remount cycle.
|
||||
// Start the ceiling at the first attach, then extend while a restore is still pending but
|
||||
// never past it. FileDiff emits 'mount' on every remount cycle, so the ceiling is armed
|
||||
// once and never re-armed here.
|
||||
const now = Date.now()
|
||||
if (ceiling.current === 0) {
|
||||
ceiling.current = now + RESTORE_CEILING_MS
|
||||
}
|
||||
if (pending.current && now < ceiling.current) {
|
||||
deadline.current = Math.min(now + RESTORE_DEADLINE_MS, ceiling.current)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user