From d924d9059c78e4067d9034c4f4120c57f12e0336 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 28 Apr 2026 21:35:15 +0200 Subject: [PATCH] refactor(transcription): drop dead existsById orphan guard from listener MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Felix #2 / Markus #1 (PR #366 review). In the synchronous-transactional path the existsById check could never return false — the rename and the propagation share one transaction, so the renamed Person is guaranteed to still exist when the listener runs. The check was forward-protection for an eventual @Async refactor but its presence today is misleading: it suggests a runtime branch that no test could reach against the real flow. Delete the call, drop the PersonService dependency from the listener, drop the now-unused PersonService.existsById, and remove the orphan-guard test (it asserted a behaviour that the synchronous path cannot produce). When async is added later the guard re-enters the codebase deliberately as part of that refactor. Refs #362 #366 Co-Authored-By: Claude Opus 4.7 --- .../PersonMentionPropagationListener.java | 6 ---- .../familienarchiv/service/PersonService.java | 4 --- .../PersonMentionPropagationListenerTest.java | 30 +------------------ 3 files changed, 1 insertion(+), 39 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListener.java b/backend/src/main/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListener.java index 84c297e2..7130b7e4 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListener.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListener.java @@ -33,16 +33,10 @@ import java.util.regex.Pattern; public class PersonMentionPropagationListener { private final TranscriptionBlockRepository blockRepository; - private final PersonService personService; @EventListener @Transactional public void onPersonDisplayNameChanged(PersonDisplayNameChangedEvent event) { - if (!personService.existsById(event.personId())) { - log.warn("Skipping mention propagation for non-existent personId {}", event.personId()); - return; - } - List blocks = blockRepository.findByMentionedPersons_PersonId(event.personId()); if (blocks.isEmpty()) { diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java index e5bab02d..33873459 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java @@ -51,10 +51,6 @@ public class PersonService { .orElseThrow(() -> DomainException.notFound(ErrorCode.PERSON_NOT_FOUND, "Person not found: " + id)); } - public boolean existsById(UUID id) { - return personRepository.existsById(id); - } - public List findCorrespondents(UUID personId, String q) { if (q != null && !q.isBlank()) { return personRepository.findCorrespondentsWithFilter(personId, q); diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java index 078b80f7..8c804f67 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java @@ -26,9 +26,6 @@ import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @@ -42,16 +39,13 @@ class PersonMentionPropagationListenerTest { @Autowired EntityManager em; private PersonMentionPropagationListener listener; - private PersonService personService; private UUID documentId; private UUID annotationId; @BeforeEach void setUp() { - personService = mock(PersonService.class); - when(personService.existsById(any())).thenReturn(true); - listener = new PersonMentionPropagationListener(blockRepository, personService); + listener = new PersonMentionPropagationListener(blockRepository); Document doc = documentRepository.save(Document.builder() .title("Letter").originalFilename("letter.pdf") @@ -170,28 +164,6 @@ class PersonMentionPropagationListenerTest { .containsExactly("Augusta Raddatz"); } - @Test - void noOps_whenPersonIdNoLongerExists_orphanedSidecarGuard() { - UUID orphanId = UUID.randomUUID(); - when(personService.existsById(orphanId)).thenReturn(false); - - TranscriptionBlock saved = saveBlock( - "Stale reference to @Ghost Name should not be rewritten.", - List.of(new PersonMention(orphanId, "Ghost Name"))); - em.clear(); - - listener.onPersonDisplayNameChanged( - new PersonDisplayNameChangedEvent(orphanId, "Ghost Name", "Resurrected Name")); - blockRepository.flush(); - em.clear(); - - TranscriptionBlock reloaded = blockRepository.findById(saved.getId()).orElseThrow(); - assertThat(reloaded.getText()).isEqualTo("Stale reference to @Ghost Name should not be rewritten."); - assertThat(reloaded.getMentionedPersons()) - .extracting(PersonMention::getDisplayName) - .containsExactly("Ghost Name"); - } - @Test void propagatesAcross200Blocks_inUnderTwoSeconds_latencyFloor() { UUID personId = savedPersonId("Auguste", "Raddatz");