Skip to content

perf(externalfiles): cache related entries - #16696

Merged
koppor merged 9 commits into
mainfrom
fixUnlinkedFiles
Aug 28, 2026
Merged

perf(externalfiles): cache related entries#16696
koppor merged 9 commits into
mainfrom
fixUnlinkedFiles

Conversation

@Siedlerchr

@Siedlerchr Siedlerchr commented Aug 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix performance issues in the Find unlinked files dialog

  • Add option to hide pdf sidepane

Steps to test

Related issues and pull requests

grafik

Closes _____

AI usage


AI CHECKLIST.md walkthrough

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • If AI tools were used, I disclosed them in the "AI usage" section and reviewed, understood, and take full ownership of all AI-generated code
  • I manually tested my changes in running JabRef (always required)
  • I added JUnit tests for changes (if applicable)
  • I added screenshots in the PR description (if change is visible to the user)
  • I added one sentence (max 20 words) to CHANGELOG.md describing the change from the user's point of view (if the change is visible to the user)
  • [/] I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Cache related entries during unlinked-file searches

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Precompute file-to-entry associations during background unlinked-file searches.
• Serve related-entry lookups from an immutable normalized-path cache.
• Add requirements, changelog coverage, and regression testing for responsive result scrolling.
Diagram

graph TD
  A["Search dialog"] -->|starts| B["Background crawler"] -->|scans| C["File system"]
  B -->|reads entries| D[("Bibliography")]
  B -->|returns| E["Search result"] -->|stores| F["Path cache"] -->|serves| A
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Lazy asynchronous memoization
  • ➕ Computes associations only for files whose result cells are rendered.
  • ➕ Can reduce initial search completion time for large result sets.
  • ➖ Adds synchronization and result-refresh complexity.
  • ➖ May show incomplete cell state and risks repeated work during scrolling.
  • ➖ Conflicts with the requirement to resolve associations before displaying results.
2. Candidate-scoped batch matching
  • ➕ Could retain only associations for files found by the crawler.
  • ➕ May reduce cache size when the library references many files outside the search tree.
  • ➖ The existing association API is entry-centric, so all bibliography entries still need evaluation.
  • ➖ Requires broader changes to association matching and candidate filtering.

Recommendation: Keep the PR's background precomputation and immutable normalized-path index. It directly removes filesystem work from rendering and matches the non-blocking-results requirement; candidate-scoped filtering could be a later optimization if profiling shows cache size or search latency concerns.

Files changed (6) +167 / -39

Enhancement (1) +14 / -0
UnlinkedFilesSearchResult.javaBundle the file tree with cached associations +14/-0

Bundle the file tree with cached associations

• Adds a null-marked record carrying the search tree and the path-indexed related-entry cache from the crawler to the dialog view model.

jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesSearchResult.java

Bug fix (2) +80 / -36
UnlinkedFilesCrawler.javaPrecompute related-entry associations in the background crawler +59/-5

Precompute related-entry associations in the background crawler

• Changes the crawler to return both the file tree and a normalized path-to-entry index. It resolves associated unlinked files once per bibliography entry, deduplicates paths, tolerates per-entry I/O failures, and publishes immutable collections.

jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java

UnlinkedFilesDialogViewModel.javaServe related entries from the completed search cache +21/-31

Serve related entries from the completed search cache

• Passes association preferences into the crawler and stores its composite result after successful completion. Related-entry queries now use normalized-path map lookups, eliminating filesystem searches during cell rendering and scrolling.

jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesDialogViewModel.java

Tests (1) +64 / -3
UnlinkedFilesCrawlerTest.javaVerify related entries are cached during crawling +64/-3

Verify related entries are cached during crawling

• Adds regression coverage proving a citation-key-matched file is indexed to its bibliography entry. Refactors crawler setup through shared preference-aware test helpers to support the expanded constructor.

jabgui/src/test/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawlerTest.java

Documentation (2) +9 / -0
CHANGELOG.mdDocument the unlinked-files scrolling freeze fix +1/-0

Document the unlinked-files scrolling freeze fix

• Adds a user-facing fixed-item noting that search results no longer freeze while scrolling in the unlinked local files dialog.

CHANGELOG.md

files.mdSpecify non-blocking unlinked-file result rendering +8/-0

Specify non-blocking unlinked-file result rendering

• Introduces a traceable requirement that related entries be resolved before display and that rendering or scrolling perform no filesystem searches.

docs/requirements/files.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Cache collapses duplicate paths ✓ Resolved 📘 Rule violation ≡ Correctness
Description
When the same citation-key filename exists in multiple configured file directories, conversion to
relative LinkedFile values and deduplication collapse the matches, after which ordered resolution
selects only the first physical file. A displayed copy in a later directory consequently has no
related cache entry and cannot be selected for linking, regressing the previous per-displayed-file
lookup behavior.
Code

jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java[R90-92]

+                    associatedFile.findIn(databaseContext, filePreferences)
+                                  .map(UnlinkedFilesCrawler::normalizePath)
+                                  .ifPresent(associatedPaths::add);
Evidence
Rule 2 requires backward compatibility: findAssociatedNotLinkedFiles searches every configured
directory and can find the same relative filename in multiple locations, but AutoSetFileLinksUtil
relativizes the matches and applies distinct, while LinkedFile equality collapses identical
relative links. The crawler then calls LinkedFile.findIn(databaseContext, filePreferences), which
delegates to ordered directory lookup and returns only the first existing path, leaving the cache
without a key for any later displayed copy.

AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope: AGENTS.md: Preserve Existing Architecture, Compatibility, and Focused Scope
jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java[87-95]
jabgui/src/main/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtil.java[224-251]
jablib/src/main/java/org/jabref/model/entry/LinkedFile.java[250-275]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[491-506]
jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesDialogViewModel.java[340-346]
jablib/src/main/java/org/jabref/logic/util/io/CitationKeyBasedFileFinder.java[74-91]
jabgui/src/main/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtil.java[213-221]
jabgui/src/main/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtil.java[248-251]
jablib/src/main/java/org/jabref/model/entry/LinkedFile.java[161-173]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[453-471]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The related-entry cache resolves each deduplicated relative associated `LinkedFile` only once. When identical citation-key filenames exist in multiple configured directories, first-match resolution caches only the first physical file, so later displayed copies are omitted, associated incorrectly, or unavailable for linking.
## Issue Context
Preserve the previous per-displayed-file matching semantics while still resolving all relationships during the background search. Preserve absolute candidate identities before deduplication, or expand each relative candidate to every matching configured directory before populating the cache, and add coverage for identical relative filenames in multiple configured file directories.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java[77-103]
- jabgui/src/main/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtil.java[213-251]
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[309-331]
- jabgui/src/test/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawlerTest.java[109-130]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Changelog retains TODO reference ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new changelog entry still uses the pre-creation TODO placeholder instead of a real issue or PR
link. This leaves the release note outside the prescribed final format.
Code

CHANGELOG.md[91]

+- We fixed freezing while scrolling results in the Search for unlinked local files dialog. TODO
Evidence
Rule 33 requires a known issue link or the documented PR-link fallback. Repository guidance says
TODO is only a pre-creation placeholder and must be replaced immediately after PR creation, while
the added entry still ends in TODO.

AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format: AGENTS.md: Maintain User-Facing CHANGELOG Entries in the Prescribed Format
CHANGELOG.md[91-91]
AGENTS.md[488-503]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new changelog entry retains a temporary `TODO` reference after the pull request has been created.
## Issue Context
Link the matching issue when one exists; otherwise replace the placeholder with this pull request's real number and URL.
## Fix Focus Areas
- CHANGELOG.md[91-91]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Cancelled search keeps crawling ✓ Resolved 🐞 Bug ☼ Reliability
Description
The newly added cache-building loop performs recursive associated-file searches for every database
entry without checking task cancellation. Closing or cancelling the wizard can therefore leave the
worker traversing configured directories long after its result has been discarded.
Code

jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java[R85-87]

+        for (BibEntry entry : databaseContext.getDatabase().getEntries()) {
+            try {
+                Collection<LinkedFile> associatedFiles = autoSetFileLinksUtil.findAssociatedNotLinkedFiles(entry);
Evidence
The changed code invokes discovery once per entry and contains no cancellation check. Both
underlying finders perform blocking recursive traversals, while cancellation only marks the
BackgroundTask cancelled and does not terminate these loops.

jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java[77-100]
jablib/src/main/java/org/jabref/logic/util/io/CitationKeyBasedFileFinder.java[81-90]
jablib/src/main/java/org/jabref/logic/util/io/BrokenLinkedFileNameBasedFileFinder.java[41-55]
jablib/src/main/java/org/jabref/logic/util/BackgroundTask.java[99-110]
jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesWizard.java[54-64]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`findRelatedEntriesByFile` starts potentially expensive recursive filesystem searches for every entry and never observes `BackgroundTask` cancellation. A cancelled wizard can leave this work running in the background.
## Issue Context
Check cancellation before entering and during the per-entry loop. Because each finder can recursively traverse large directory trees, propagate cancellation or interruption into finder traversal so an in-progress entry can stop promptly as well.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java[71-103]
- jablib/src/main/java/org/jabref/logic/util/io/CitationKeyBasedFileFinder.java[74-91]
- jablib/src/main/java/org/jabref/logic/util/io/BrokenLinkedFileNameBasedFileFinder.java[41-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread jabgui/src/main/java/org/jabref/gui/externalfiles/UnlinkedFilesCrawler.java Outdated
Comment thread CHANGELOG.md Outdated
}

private static Path normalizePath(Path path) {
return path.toAbsolutePath().normalize();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Generated with Claude Code

Suggestion carried over from #16695: toAbsolutePath().normalize() is lexical, so when the search directory is a symlink/alias of the configured file directory the crawled path and the path from findIn(...) never match and the file loses its "Select entry to link" dropdown. Using filesystem identity fixes it (used on both sides — here and in getRelatedEntriesForFiles):

private static Path normalizePath(Path path) {
    try {
        return path.toRealPath();
    } catch (IOException e) {
        return path.toAbsolutePath().normalize();
    }
}

Test that fails without it (Linux/macOS): create files/ with author000.pdf, a library with entry author000 whose main file directory is files/, Files.createSymbolicLink(link, files), search in link, then getRelatedEntriesForFiles(link.resolve("author000.pdf")) must return the entry (@DisabledOnOs(OS.WINDOWS)).

taskActiveProperty.setValue(false);
})
.onSuccess(treeRoot -> treeRootProperty.setValue(Optional.of(treeRoot)));
.onSuccess(searchResult -> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Generated with Claude Code

Suggestion carried over from #16695: onEnteringPage calls startSearch() again when the user goes back to page 1 and forward while the first search is still running. The older task then finishes later and overwrites relatedEntriesByFile/treeRootProperty of the newer search (and a cancelled search still does the full entry lookup, which is the expensive part). Two small guards cover both:

if (findUnlinkedFilesTask != null) {
    findUnlinkedFilesTask.cancel();
}
UnlinkedFilesCrawler task = new UnlinkedFilesCrawler(...);
findUnlinkedFilesTask = task;
task.onSuccess(searchResult -> {
        if (findUnlinkedFilesTask != task) {
            return; // superseded by a newer search
        }
        ...
    })

plus in UnlinkedFilesCrawler.call(): isCancelled() ? Map.of() : findRelatedEntriesByFile() after searchDirectory(...) (the executor drops a cancelled task's result anyway).

koppor and others added 2 commits August 26, 2026 23:44
Resolve associated files in every configured file directory instead of the first match, key the cache by real path so symlinked search directories still match, stop the entry lookup once the search is cancelled, and ignore results of a superseded search in the dialog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZXuvrbXanmtZnE7kKm9EN
koppor and others added 2 commits August 27, 2026 01:18
The page only places the preview pane into the scene once a tree root exists, so the test never found the button it tried to click.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZXuvrbXanmtZnE7kKm9EN
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZXuvrbXanmtZnE7kKm9EN
@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Aug 27, 2026
Siedlerchr and others added 2 commits August 27, 2026 20:30
* main:
  Chore(deps): Bump net.ltgt.nullaway from 3.1.0 to 3.2.0 in /jablib (#16712)
  Chore(deps): Bump org.jsoup:jsoup from 1.23.1 to 1.23.2 in /versions (#16713)
  Chore(deps): Bump com.autonomousapps:dependency-analysis-gradle-plugin (#16709)
  Chore(deps): Bump com.autonomousapps:dependency-analysis-gradle-plugin (#16710)
  Chore(deps): Bump net.ltgt.errorprone from 5.1.0 to 5.1.1 in /jablib (#16711)
  Run the CAYW JavaFX picker in the native jabsrv image (#16634)
  Run PR tests when a submodule pointer changes (#16699)
  New Crowdin updates (#16701)
  Chore(deps): Bump jablib/src/main/resources/csl-styles from `0b07219` to `0819c0e` (#16685)
  First class Theme Support in JabRef (#15798)

# Conflicts:
#	jabgui/src/main/java/org/jabref/gui/externalfiles/FindUnlinkedFilesAction.java
koppor added a commit to JabRef/jabref-koppor that referenced this pull request Aug 28, 2026
@JabRef JabRef deleted a comment from github-actions Bot Aug 28, 2026
@github-actions github-actions Bot added status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers and removed status: changes-required Pull requests that are not yet complete labels Aug 28, 2026

@koppor koppor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried out. Works.

@koppor
koppor added this pull request to the merge queue Aug 28, 2026
@github-actions github-actions Bot added the status: to-be-merged PRs which are accepted and should go into the merge-queue. label Aug 28, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 28, 2026
@koppor
koppor added this pull request to the merge queue Aug 28, 2026
@koppor

koppor commented Aug 28, 2026

Copy link
Copy Markdown
Member

In merge queue macOS silicon signature validation failed - retrying

image

Merged via the queue into main with commit a07dcb1 Aug 28, 2026
74 checks passed
@koppor
koppor deleted the fixUnlinkedFiles branch August 28, 2026 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: external-files component: pdf-viewer status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers status: to-be-merged PRs which are accepted and should go into the merge-queue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants