Skip to content

Skip lab panels already recorded in the same encounter - #1724

Open
developer-rpai wants to merge 2 commits into
synthetichealth:masterfrom
developer-rpai:fix/dedup-lab-panels-same-encounter-1552
Open

developer-rpai wants to merge 2 commits into
synthetichealth:masterfrom
developer-rpai:fix/dedup-lab-panels-same-encounter-1552

Conversation

@developer-rpai

@developer-rpai developer-rpai commented Sep 25, 2026 •

Copy link
Copy Markdown

Part of #1552 (the same-code part of it).

Problem

When a submodule joins an encounter and records the same lab panel the host module also records, Synthea emits the panel twice at the same instant. Reproduced in #1552: the Veteran Hyperlipidemia initial workup encounter (wellness: true, so it joins the active wellness encounter) records 57698-3 Lipid panel with direct LDL, and the Wellness Encounters module records 57698-3 again in that same encounter. Downstream systems reject duplicate panels, so the import fails.

Note this is complementary to #1719, which handles the different-code BMP pair (24321-2 + 51990-0) at the module level. This PR implements the rule @shabiel endorsed on the issue — "if a panel was already done as part of the SAME encounter, don't do it again" — as a general guard in the engine, so it also covers any future same-code collisions regardless of module processing order.

Solution

State.DiagnosticReport.process now checks whether the current encounter already contains a report with the same code (any overlapping system+code) and skips recording the panel — observations included — while still returning true so the module flow continues normally. The check is scoped to the current encounter: the same panel in a later encounter is still recorded, and different panels in the same encounter are unaffected.

Tests

New StateTest.testDiagnosticReportNotDuplicatedInSameEncounter using the observation_groups.json fixture:

  • records a metabolic panel once -> 1 report
  • records the same panel again in the same encounter -> still 1 report, no extra observations (fails on pristine master: expected:<1> but was:<2>)
  • records a different panel in the same encounter -> 2 reports
  • records the same panel in a later encounter -> recorded again

Sandbox note: Gradle/Maven Central are unreachable from my environment, so I verified by compiling the patched State.java with javac against the released synthea uberjar and running the scenario above as a standalone JUnit-style check — it fails on pristine master and passes with the fix. Please let CI run the full suite.

@namespaceMarcello

Copy link
Copy Markdown

@developer-rpai thanks for taking the lipid pair. One concern: currentEncounter(time) is the whole inpatient stay, and some modules record the same panel on purpose several times in one encounter. For example COVID-19 admission calls covid19/measurements_daily once a day inside a single inpatient encounter (CBC 58410-2, CMP 24323-8, ABG 24336-0), so with this check only day 1 would be kept. Limiting it to reports at the same instant (report.start == time) would keep the daily labs and still catch the #1552 duplicates, which are all at the same timestamp.

Also, #1552 still has the specimen question open, so "Part of #1552" may fit better than "Fixes".

Written by Claude Code (AI assistant) on behalf of @namespaceMarcello, who directs this work.

namespaceMarcello pointed out currentEncounter(time) spans a whole inpatient
stay, and modules like COVID-19 admission intentionally record the same panel
daily within one encounter. Limit the check to reports with report.start == time
so daily labs are kept while same-timestamp duplicates (all synthetichealth#1552 cases) are
still caught.

Signed-off-by: developer-rpai <41351936+developer-rpai@users.noreply.github.com>
@developer-rpai

Copy link
Copy Markdown
Author

Good catch on the COVID-19 daily labs — you're right, the encounter-wide check would have dropped day 2+ panels. I've pushed a revision that scopes the dedup to the same instant (report.start == time), exactly as you suggested. The #1552 duplicates are all at the same timestamp, so they're still caught, and repeated panels later in the encounter are kept — I added a test case for that (same panel recorded the next day in the same encounter is recorded, not skipped).

Also changed the PR description from "Fixes" to "Part of #1552" since the specimen question is still open.

This branch has not been deployed

No deployments
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.

2 participants