Skip to content

fix(seek-slider): correct cluster seek rebuild and live drag index#298

Merged
lstein merged 1 commit into
masterfrom
lstein/fix/seek-slider-cluster-rebuild
Jun 5, 2026
Merged

fix(seek-slider): correct cluster seek rebuild and live drag index#298
lstein merged 1 commit into
masterfrom
lstein/fix/seek-slider-cluster-rebuild

Conversation

@lstein
Copy link
Copy Markdown
Owner

@lstein lstein commented Jun 5, 2026

Problem

Reproduce: select an image cluster, enter swiper view, run the sequential slideshow until it stops on the last image, then drag the seek-slider back to image #1.

  • It landed on the wrong image (e.g. Workflow/fix release workflow #3 instead of Bump version #1) with a corrupted position badge.
  • Swiping left then showed the badge as "0" and "-1".
  • It could also occur without the slideshow (harder to reproduce — any seek to an image not currently in the buffer).

Root cause

SwiperManager.seekToSlideIndex rebuilds the windowed slide buffer when the target isn't loaded. The old loop stepped the global album index and the search index together (globalIndex + i, searchIndex + i). That assumes search-result order is contiguous in global-album index, which is false for clusters/searches — their members are scattered across the album. As a result it:

  • loaded album-adjacent images instead of the adjacent cluster images, and
  • with the -2 origin, tagged the prepended slides with out-of-range search indices (-1, -2).

The position badge renders index + 1 (score-display.js), so those mistagged slides displayed as "0" and "-1", and a slide actually showing image #1 could carry a stale search index and read "3".

Fix

  • swiper.js — the rebuild now branches on mode: in search/cluster mode it resolves each neighbour's global index through searchToGlobal(searchIndex + i) and clamps to [0, totalCount); album mode keeps the contiguous globalIndex + i stepping. No slide is ever loaded with the wrong picture or an out-of-range index.
  • seek-slider.js — a pre-existing live-drag off-by-one, exposed once the release-time display became correct: onSliderInput passed targetIndex + 1 to showCluster/showSearchScore, which already add 1, so the badge read one too high while dragging. Now passes the 0-based targetIndex, matching the album branch and the release-time path.

Tests

  • tests/frontend/seek-search-rebuild.test.js — verifies the rebuild loads adjacent cluster images, never tags slides with out-of-range search indices, and lands on image Bump version #1 with the correct badge. Fails on the old code, passes on the fix.
  • tests/frontend/seek-slider-live-index.test.js — verifies the live-drag badge uses the 0-based index for cluster and scored-search results. Fails on the old code, passes on the fix.
  • Full frontend suite: 349 passed (24 suites); lint + prettier clean.

🤖 Generated with Claude Code

Seeking back to an image not in the buffer (e.g. after a sequential
slideshow stops at the last image of a cluster) could land on the wrong
image and show a corrupted position badge ("3" for image #1, "0"/"-1"
when swiping left).

seekToSlideIndex rebuilt the buffer by stepping globalIndex and
searchIndex together (globalIndex + i, searchIndex + i). That assumes
search-result order is contiguous in global-album index, which is false
for clusters/searches — their members are scattered. It loaded
album-adjacent images and, with the -2 origin, tagged prepended slides
with out-of-range search indices (-1, -2). The badge renders index + 1,
so those surfaced as "0" and "-1", and mistagged slides corrupted the
displayed position. The rebuild now resolves each neighbour through
searchToGlobal in search mode and clamps to [0, totalCount).

Exposed by the above fix, the live seek-slider badge also double-counted:
onSliderInput passed targetIndex + 1 to showCluster/showSearchScore,
which already add 1, so the position read one too high while dragging
(release used a different, correct path). Pass the 0-based targetIndex.

Adds regression tests for both paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lstein lstein merged commit ae89c9e into master Jun 5, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant