feat(encounters): the lab moment, the condition side, and closing a checkup

A lab panel files itself against the visit it came from, and never has to. The
OCR review and the manual form both offer the suggestion through the one shared
field, anchored on the draw date rather than on now, so backdating a reading
moves the offer with it. The commit writes one link PER RESULT ROW, which is
why the join is m:n: a marker re-run on a different day belongs to its own
visit. Best-effort by design — the readings are the write that matters and must
not be lost to a link that could not be made.

The condition side gets a Visits about this card with an action that pre-links
the episode. From the episode side only, and that is a decision: an episode
spans weeks and a visit is a point, so matching the other way would be wrong
often enough to teach a person to ignore every suggestion in the product.

A due checkup gains a second action beside erledigt. Filing the visit as done
satisfies the checkup through the same forward-only, idempotent primitive the
checkbox uses, so doing both is one satisfaction and no error. The two actions
answer different questions — one says it happened, the other says where.

An appointment now appears where a person looks, and NEITHER surface relaxes
the reminder-table exclusion that keeps it out of the preventive-care lists.
Both read the visit table: a quiet line under the dashboard checkup block for
anything inside two weeks, and one rail item for today or tomorrow. A diff in
either that touches origin is the wrong fix.

A visit write now also refreshes the reminder reads. Closing a checkup moves
its next-due date on three surfaces that would otherwise keep showing it due
until their own poll.

OpenAPI regenerated in the same commit.
This commit is contained in:
Marc-André Bombeck committed 2026-08-08 14:08:09 +02:00
1 parent be9c79974f
commit c47122ccfe
36 files changed
+924 -192

No files matched your search

+19 -2
View File
@@ -9176,6 +9176,10 @@ paths:
enum:
- MANUAL
- OCR
encounterId:
type: string
minLength: 1
maxLength: 40
required:
- takenAt
responses:
@@ -9477,6 +9481,10 @@ paths:
type: string
minLength: 1
maxLength: 64
encounterId:
type: string
minLength: 1
maxLength: 40
required:
- rows
responses:
@@ -9713,6 +9721,12 @@ paths:
type: string
minLength: 1
maxLength: 40
- in: query
name: episodeId
schema:
type: string
minLength: 1
maxLength: 40
- in: query
name: limit
schema:
@@ -16974,7 +16988,7 @@ components:
enabledHeroItemKinds:
description: Today-highlight item kinds in catalogue order. Missing means every current kind is enabled; an empty array
disables all kinds.
maxItems: 8
maxItems: 9
type: array
items:
type: string
@@ -16987,6 +17001,7 @@ components:
- ecg_new_recording
- tension_window
- same_time_baseline
- upcoming_visit
baseUpdatedAt:
description: "Optimistic-concurrency base token: the `updatedAt` the client last read for this resource. Omit it for the
legacy unconditional write (older clients are unaffected). When present, the write is guarded on the stored
@@ -38612,6 +38627,7 @@ components:
- ecg_new_recording
- tension_window
- same_time_baseline
- upcoming_visit
description: Closed rail-item kind.
itemKey:
description: Stable dismiss identity, namespaced `<kind>:...`. Present only on the observational kinds (milestone /
@@ -38894,7 +38910,7 @@ components:
enabledHeroItemKinds:
description: Today-highlight item kinds in catalogue order. Missing means every current kind is enabled; an empty array
disables all kinds.
maxItems: 8
maxItems: 9
type: array
items:
type: string
@@ -38907,6 +38923,7 @@ components:
- ecg_new_recording
- tension_window
- same_time_baseline
- upcoming_visit
updatedAt:
description: "Optimistic-concurrency token: the stored row's `updatedAt` at read/write time. Echo it back as
`baseUpdatedAt` on the next write. Opaque."