Files
pad/web/e2e
xarmian 84ddb3f693 fix(web): the list cursor no longer snaps back while the pane follows j/k (BUG-3204) (#1863)
* test(e2e): a list change while the pane follows j does not snap the cursor back (BUG-3204)

* fix(web): a list change while the pane follows j/k no longer snaps the cursor back (BUG-3204)

The collection route keeps the row highlight on the open pane's item: an
effect sets the cursor to ?item='s row whenever the list changes. j/k move the
cursor at once and the pane follows 140ms later, so a list change inside that
window snapped the cursor back to the old item, and the follow snapped it
forward again: a visible flicker, and attachment-viewer-owners' owner-2 flake
(CI: alpha, alpha, BRAVO, alpha after one j).

While a follow is pending the cursor is the newer intent, so the effect
yields; the follow's own ?item= change re-runs it.

Lever (e2e/bug-3204-cursor-snapback.spec.ts holds the /items-changes fetch a
rename triggers until j is pressed): main 10/10 fail, this 20/20 pass.

* fix(web): the cursor follows a reactive pending target, and a click supersedes a pending follow (BUG-3204, codex r1)

Codex r1: the first fix gated the snap-back on the non-reactive timer handle,
so a follow that ended without navigating (target deleted, already open)
left the cursor blank with nothing to re-run the effect, and a click during
the debounce was overridden by the follow.

pendingFollow {id, fromRef} is $state. While set, the snap-back targets that
row by id. It clears when ?item= reaches the row, when the follow opens
nothing, or when ?item= moves by another door, which also cancels the follow.

The spec freezes the page clock and holds the list fetch that carries the
change, so each case is deterministic. Main: case 1 (snap-back) and case 3
(click overridden) fail 10/10, and case 2 passes. Fix: 180/180 at 8 workers.

* fix(web): pendingFollow is per-session state; the follow timer keeps its identity fence first (BUG-3204)

The collection identity gate caught both: a new $state the identity reset
did not clear, and a timer whose identityHeld check had moved into a helper.
resetPerSessionState clears pendingFollow; the timer checks identityHeld
before anything else; the gate rows are re-reviewed.

* fix(web): a follow the controller would drop, or that never lands, releases its pending target (BUG-3204, codex r2)

follow() reports false when a pane navigation is in flight, since the
controller silently drops the open then. A follow that navigates arms a
fenced settle timer that drops a target still pending after 1s, covering a
goto superseded without ?item= moving. The identity gate's timer inventory
and rows are updated. Case 2 of the spec now claims only what it exercises.

* fix(web): the settle check shares the follow's timer handle, so teardown clears it (BUG-3204, codex r3)
2026-10-07 17:42:35 -04:00
..