Skip to content

Fix OpenSearch index staleness when encounters assigned to individuals#1547

Open
JasonWildMe wants to merge 3 commits into
mainfrom
fix/encounter-reindex-individual-1514
Open

Fix OpenSearch index staleness when encounters assigned to individuals#1547
JasonWildMe wants to merge 3 commits into
mainfrom
fix/encounter-reindex-individual-1514

Conversation

@JasonWildMe
Copy link
Copy Markdown
Collaborator

@JasonWildMe JasonWildMe commented Apr 17, 2026

Reopens work from closed PR #1535 on a clean branch off main, as a foundation for also fixing #1514.

Summary

OpenSearch index was not being updated when encounters were assigned to / removed from individuals through various code paths. This PR addresses the direct individualId / individualDisplayName staleness on affected encounters. Issue #1514 (stale individualNumberEncounters on sibling encounters) is related but will be addressed in a follow-up commit on this branch.

Root cause

  • skipAutoIndexing flag in Encounter.processPatch() prevented auto-indexing
  • Several servlets / JSPs didn't trigger reindex after modifying encounter-individual relationships
  • Added explicit IndexingManager.addIndexingQueueEntry() calls with null checks in all affected code paths

Files changed

  • Encounter.java: reset skipAutoIndexing and trigger reindex at end of processPatch()
  • IndividualAddEncounter.java: reindex encounter after adding to individual
  • IndividualRemoveEncounter.java: reindex encounter AND old individual after removal
  • IndividualCreateForProject.java: reindex encounter after creating new individual
  • MarkedIndividual.java: reindex all transferred encounters and both individuals in mergeIndividual()
  • iaResultsSetID.jsp: reindex encounter after ID confirmation in all 3 code paths

Related

Test plan

  • Verify OpenSearch query results match JDOQL for individualID IS NULL filter
  • Confirm encounter reindexes when assigned to individual via UI
  • Confirm encounter reindexes when removed from individual
  • Confirm encounters reindex when individuals are merged

Find missed Encounter/individual reindexing opportunities
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 50.74%. Comparing base (14f3a08) to head (4f6cb01).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1547   +/-   ##
=======================================
  Coverage   50.74%   50.74%           
=======================================
  Files         281      281           
  Lines       10468    10468           
  Branches     3238     3251   +13     
=======================================
  Hits         5312     5312           
- Misses       4891     4897    +6     
+ Partials      265      259    -6     
Flag Coverage Δ
backend 50.74% <ø> (ø)
frontend 50.74% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

JasonWildMe and others added 2 commits April 17, 2026 10:13
When a MarkedIndividual's encounter list changes at a mutation site that
was not already queueing the individual for a deep reindex, sibling
encounters retained stale denormalized fields in OpenSearch, including
individualNumberEncounters, individualFirstEncounterDate, etc.

Per Codex design review: queue the MarkedIndividual itself — not each
encounter — because IndexingManager.addIndexingQueueEntry on an
individual triggers opensearchIndexDeep, which cascades to every
encounter with built-in per-id dedup.

Adds a shared helper
IndexingManager.queueIndividualsByIdForDeepReindex(Shepherd, Collection<String>)
and calls it post-commit at the missed mutation sites:

- AnnotationEdit — annotation-level swap/assign of individuals
- EncounterForm — manualID path on new encounter submission
- IBEISIA.assignFromIAAPI — IA-driven individual assignment
- EncounterVMData — Visual Matcher "matchID" path
- ImportIA — per-name individual creation/reuse
- merge.jsp — individual merge followed by encounter reassignment
- BulkImporter / api.BulkImport — both fg and bg paths via
  getTouchedIndividualIds() on the importer
- StandardImport — end-of-import sweep of individualCache values
- ImportSRGD — rows that create/attach individuals
- ImportExcelMetadata — first and second flows (latter is dead but
  kept defensive)
- ImportTask.deleteWithRelated — returns surviving individual ids to
  the BulkImport caller for post-commit queueing
- DeleteImportTask — same, inline

Deliberately not addressed here (covered by #1548): pre-existing
pre-commit queueing in Encounter.processPatch, MarkedIndividual.mergeIndividual,
and iaResultsSetID.jsp. Those race against the enclosing commit and
survive rollback; moving them requires a cross-cutting refactor that
would balloon this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1. IndexingManager.queueIndividualsByIdForDeepReindex was dereferencing
   the caller's Shepherd, which in servlets is closed by the finally
   block before the queue call runs (closeDBTransaction). The underlying
   PM is closed, so getMarkedIndividualQuiet returned null and every
   affected site silently queued nothing. Open a fresh short-lived
   read-only Shepherd for the id->object resolution instead.

2. StandardImport.loadIndividual only cached newly-created individuals
   in individualCache. Pre-existing individuals that had encounters
   added by the import were never queued for deep reindex — exactly the
   stale-sibling case #1514 is about. Also cache existing individuals
   when they are touched via addEncounter.

3. merge.jsp queued inside the finally block unconditionally, so the
   rollback path still reached the queue. Added a mergeSuccess flag so
   only the happy path triggers reindex queueing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JasonWildMe JasonWildMe requested a review from naknomum April 17, 2026 18:21
@JasonWildMe JasonWildMe self-assigned this Apr 17, 2026
@naknomum naknomum added this to the 10.10.5 milestone May 5, 2026
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.

3 participants