mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 14:30:13 +00:00
3ce7c5ce8b
* fix(web): pane Back holds the restored scroll position until the pane settles, so a late-loading section no longer leaves the reader short (BUG-3250)
#1604 (BUG-3240) made the body render as soon as the replay is applied, so
PaneHost's restore now lands about 100ms after onReady, before other parts of
the pane settle: the attachment strip's loading placeholder disappears and the
timeline's loader becomes its content. Scroll anchoring and clamping then
moved scrollTop, and a reader returning near the end of a long item landed
70-90px short. bug-2182's Back leg at 8 workers: 26/100 failed on main, 0/100
on the parent.
After the first apply the restore now holds its target until
RESTORE_CAP_MS: every resize re-applies it. The hold ends at the cap or at the
first reader move: a wheel, touch or key gesture, or a scroll away from our
last assignment while scrollHeight held still (a scrollbar drag). A clamp or
an anchoring shift changes the height; our own assignment lands on the value
we set.
Legs pin each rule with a deterministic 200px shift: re-applied during the
hold; a drag honoured; a gesture that scrolls nothing ends it; nothing after
the cap. Main's PaneHost fails only the first; mutants of each rule fail only
their own. Gate: the Back leg 300/300 at 8 workers.
RESTORE_CAP_MS stays 2500 (TASK-3248's receipt): with a ~300-frame op-log
the first apply reaches 1693ms and 9/100 never applied by 2500 (the parent:
6/100), so lowering it would cut into a tail that predates BUG-3240.
Claude-Session: https://claude.ai/code/session_01NidgPePY7UvHcEJCMkD2Qz
* fix(web): a pane restore ends when the pane leaves its item, and runs without scroll anchoring (BUG-3250 codex round 1)
Codex round 1 on ec58ea1f:
- (b) P1: a hold still live when the reader drills on could reach the next
item, since a drill is a pushState and never hits the popstate cancel.
Measured: today the drill replaces every child of the pane, so the hold's
ResizeObserver is left on detached nodes and B was never written (3/3, B
rendering 419-504ms into the hold). The protection was incidental, so
handleItemReady now cancels a live restore on onReady(false), which
ItemDetail reports the moment its item stops matching the requested ref.
A guard leg pins the outcome.
- (c) P2: a scroll-anchoring shift can move scrollTop with no height change,
which the reader rule would take for the reader. The pane runs without
scroll anchoring for the life of the restore, so a layout shift moves
scrollTop only by clamping, which changes the height.
Claude-Session: https://claude.ai/code/session_01NidgPePY7UvHcEJCMkD2Qz
* fix(web): a same-item reload no longer cancels a pane restore (BUG-3250 codex round 2)
Round 1 cancelled a live restore on any onReady(false). Codex round 2: a
same-item loadData also reports not-ready (loading = true), so a reload
during the restore would drop a legitimate one. Cancel only when the
requested ref (paneMintForRoute) or the workspace is no longer the one the
restore started under; the drill guard leg still covers the cross-item case.
Gate: the Back leg x300 at 8 workers 300/300; the BUG-3250 legs 15/15.
Claude-Session: https://claude.ai/code/session_01NidgPePY7UvHcEJCMkD2Qz
* fix(web): the pane restore's cancel compares the immediate item, not the coalesced mint ref (BUG-3250 codex round 3)
paneMintForRoute is held on the old item while a same-path popstate settles
(paneMintSettle), so comparing it could miss an item change inside that
window. The restore now captures and compares openItemRef; onPopState still
cancels on every traversal, and a same-item reload still does not cancel.
Claude-Session: https://claude.ai/code/session_01NidgPePY7UvHcEJCMkD2Qz