Fix duplicate finder progress counter incrementing on empty queue polls#15781
Conversation
Review Summary by QodoFix duplicate finder progress counter incrementing logic
WalkthroughsDescription• Fixed progress counter incrementing on empty queue polls • Counter now increments only when duplicate pair shown • Corrected title binding to use observable property • Updated changelog with fix description Diagramflowchart LR
A["Empty queue poll"] -->|Before| B["Counter incremented"]
C["Duplicate pair found"] -->|Before| B
A -->|After| D["Counter unchanged"]
C -->|After| E["Counter incremented"]
E --> F["Dialog title updated"]
B --> G["Incorrect progress display"]
F --> H["Correct progress display"]
File Changes1. jabgui/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java
|
Code Review by Qodo
Context used✅ Tickets:
🎫 Duplicate finder counter makes no sense 1. duplicateProgress.set() off FX thread
|
|
Sorry for the confusion and the noise on this PR, I know that the auto-merge was already enabled,but I had some problems. During the process of addressing review feedback, I accidentally performed a force push which invalidated the previous approval and caused CI failures related to that. While trying to fix the resulting issues, the CHANGELOG entry ended up duplicated multiple times due to repeated rebasing, and the CI kept failing. To avoid further complications on an already messy history, I decided to close this PR and open a clean one from scratch with a single commit on top of upstream/main. The fix itself is unchanged, same two line logic correction |
| DuplicateResolverType resolverType = askAboutExact ? DuplicateResolverType.DUPLICATE_SEARCH_WITH_EXACT : DuplicateResolverType.DUPLICATE_SEARCH; | ||
|
|
||
| // Increment only when a pair is actually shown to the user | ||
| duplicateProgress.set(duplicateProgress.getValue() + 1); |
There was a problem hiding this comment.
1. duplicateprogress.set() off fx thread 📘 Rule violation ☼ Reliability
duplicateProgress (a JavaFX property bound to the dialog title) is incremented inside verifyDuplicates(), which is executed via a BackgroundTask and therefore may run off the JavaFX Application Thread. Updating an FX-observed property from the worker thread can notify bindings/listeners on the wrong thread, causing intermittent UI exceptions, crashes, or undefined behavior.
Agent Prompt
## Issue description
`duplicateProgress` is a JavaFX `SimpleIntegerProperty` that is bound into the dialog title, but it is currently incremented inside `verifyDuplicates()` while that method runs via `BackgroundTask` on a worker thread. Because bindings/listeners may be notified on the worker thread, this can drive JavaFX UI updates off the FX Application Thread, leading to unstable UI behavior or runtime exceptions.
## Issue Context
- `verifyDuplicates()` is executed via `BackgroundTask.wrap(this::verifyDuplicates)`, and in JabRef’s `UiTaskExecutor` the task `call()` runs on a background thread.
- `askResolveStrategy()` binds `dialog.titleProperty()` to `duplicateProgress`, making `duplicateProgress` a UI-observed property.
- The codebase already marshals UI-related changes to the JavaFX thread (e.g., `duplicateTotal` is updated via `runAndWaitInJavaFXThread`).
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java[98-101]
- jabgui/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java[122-166]
- jabgui/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java[151-156]
## Suggested approach
Move the `duplicateProgress` increment so it always executes on the JavaFX Application Thread (e.g., into the existing `UiTaskExecutor.runAndWaitInJavaFXThread(...)` block around `askResolveStrategy()` or by wrapping just the increment in `UiTaskExecutor.runInJavaFXThread(...)`), and remove the worker-thread `duplicateProgress.set(...)` call.
Optionally, ensure the dialog title binding is unbound after the dialog is closed to avoid keeping bindings/listeners alive longer than needed.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
* upstream/main: Update PULL_REQUEST_TEMPLATE.md (#15788) New Crowdin updates (#15787) Update heylogs to 0.18.0 and use github-actions format (#15786) Grand refactoring of the AI features (#15688) Chore(deps): Bump com.fasterxml:aalto-xml in /versions (#15782) Chore(deps): Bump org.junit:junit-bom from 6.0.3 to 6.1.0 in /versions (#15783) Fix default value for unwanted characters (#15743) Fix runner tag Fix runner for JBang (PR) Fix duplicate finder progress counter incrementing on empty queue polls (#15781) Refine JabKit CLI: positional input argument and check command group (#15759) Ignore exception in unregisterListener to prevent exception (#15761) Fix wrong usage of "key" (#15779) Fix Hayagriva export to nest identifiers under serial-number (#15750)
Related issues and pull requests
Closes #11848
PR Description
The duplicate finder progress counter in DuplicateSearch.java was being incremented on every iteration of the polling loop, including iterations where the queue was empty and no pair was shown to the user. This fix moves the increment to the point where a duplicate pair is actually presented to the user, and corrects the title binding to use the observable property directly instead of a static captured value
Steps to test
AI usage
Claude Code (claude-sonnet-4-6) -> Only used to find the source of the problem and a way to correct it
Checklist
CHANGELOG.mdin a way that can be understood by the average user (if change is visible to the user)