fix(dupe): resync viewer session after keep-best/delete-group; harden post-prune index #108

Merged
ValleyGeek merged 2 commits from 0.1.35/issue-99-dupe-viewer-resync into main 2026-06-20 00:38:41 +00:00
Member

Summary

  • Pressing Keep Best or Delete Group (X) while in the single image viewer advanced the active duplicate group's data but never resynced the viewer, so the displayed image, carousel, and filmstrip stayed pointed at the old group (#93, #99). _on_dupe_group_prev/_on_dupe_group_next and _on_dupe_tag_filter_changed already call _resync_dupe_viewer_session() after switching groups; _on_dupe_keep_best and _on_dupe_delete_group are now brought in line with that pattern.
  • Closing that gap exposed a latent crash: _apply_dupe_group_filter's call to _refresh_tag_filter_views resolves the viewer's prior proxy rows against the already-updated filter (group filters invalidate the proxy synchronously), which can yield a prior-path list shorter than the captured prior index, raising IndexError in _pick_post_prune_index before the explicit resync ever ran. Hardened with a defensive clamp — the immediate, authoritative _resync_dupe_viewer_session() call still supersedes whatever index this picks for the duplicate-navigation paths.

Fixes #93, #99.

Threading notes: no worker threads involved; all changes are main-thread Qt slot/widget code.

Test plan

  • Added test_dupe_delete_group_resyncs_viewer_with_hide_deleted (issue #93 repro) and test_dupe_keep_best_resyncs_viewer_index_to_smaller_group (issue #99 repro) to tests/test_pr8_viewer.py
  • pytest — 365 passed, 1 skipped
  • ruff check . && ruff format --check .
  • ./scripts/check-version-bump.sh — VERSION bumped 0.1.35 → 0.1.36 (compiled inputs changed)
  • ./scripts/smoke-ui-exit.sh — clean Qt teardown
  • Verified this branch produces a real dev build via the now-fixed CI pipeline (#106/#107)

🤖 Generated with Claude Code

## Summary - Pressing Keep Best or Delete Group (`X`) while in the single image viewer advanced the active duplicate group's *data* but never resynced the viewer, so the displayed image, carousel, and filmstrip stayed pointed at the old group (#93, #99). `_on_dupe_group_prev`/`_on_dupe_group_next` and `_on_dupe_tag_filter_changed` already call `_resync_dupe_viewer_session()` after switching groups; `_on_dupe_keep_best` and `_on_dupe_delete_group` are now brought in line with that pattern. - Closing that gap exposed a latent crash: `_apply_dupe_group_filter`'s call to `_refresh_tag_filter_views` resolves the viewer's prior proxy rows against the already-updated filter (group filters invalidate the proxy synchronously), which can yield a prior-path list shorter than the captured prior index, raising `IndexError` in `_pick_post_prune_index` before the explicit resync ever ran. Hardened with a defensive clamp — the immediate, authoritative `_resync_dupe_viewer_session()` call still supersedes whatever index this picks for the duplicate-navigation paths. Fixes #93, #99. Threading notes: no worker threads involved; all changes are main-thread Qt slot/widget code. ## Test plan - [x] Added `test_dupe_delete_group_resyncs_viewer_with_hide_deleted` (issue #93 repro) and `test_dupe_keep_best_resyncs_viewer_index_to_smaller_group` (issue #99 repro) to `tests/test_pr8_viewer.py` - [x] `pytest` — 365 passed, 1 skipped - [x] `ruff check . && ruff format --check .` - [x] `./scripts/check-version-bump.sh` — VERSION bumped 0.1.35 → 0.1.36 (compiled inputs changed) - [x] `./scripts/smoke-ui-exit.sh` — clean Qt teardown - [x] Verified this branch produces a real dev build via the now-fixed CI pipeline (#106/#107) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Pressing Keep Best or Delete Group (X) while in the single image viewer
advanced the active duplicate group but never resynced the viewer, so the
displayed image, carousel, and filmstrip stayed pointed at the old group
(#93, #99). _on_dupe_group_prev/next and _on_dupe_tag_filter_changed already
call _resync_dupe_viewer_session() after switching groups; _on_dupe_keep_best
and _on_dupe_delete_group are now brought in line with that pattern.

Closing that gap exposed a latent crash: _apply_dupe_group_filter's call to
_refresh_tag_filter_views resolves the viewer's prior proxy rows against the
already-updated filter (group filters invalidate the proxy synchronously),
which can yield a prior-path list shorter than the captured prior index,
raising IndexError in _pick_post_prune_index before the explicit resync ever
ran. Clamp prior_index defensively there; the immediate, authoritative
_resync_dupe_viewer_session() call still supersedes whatever index this
picks for the duplicate-navigation paths.

Threading notes: no worker threads involved; all changes are main-thread
Qt slot/widget code.
docs: PR-prep for issues 93/99 - bump to 0.1.36
All checks were successful
CI / lint (push) Successful in 19s
CI / test (push) Successful in 2m43s
CI / windows-exe (push) Successful in 10m37s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 17m33s
CI / build-appimage (push) Successful in 0s
361d23ee40
Bump VERSION to the next canonical release (compiled inputs changed on
this branch, confirmed via ./scripts/compiled-inputs-changed.sh
origin/main) and record the fix in CHANGELOG.md under [0.1.36].

No USER_GUIDE.md changes needed: the guide's existing Keep Best/Delete
Group description ("advance to the next group") already matches the
fixed behavior - it just wasn't fully implemented for the single-image
viewer case before this fix.
ValleyGeek deleted branch 0.1.35/issue-99-dupe-viewer-resync 2026-06-20 00:38:41 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ai-collab/bulk-image-organizer!108
No description provided.