Restore what each medication was supposed to move

The register said the drug comes back with no statement of what it was
for, which is exactly what a pinned efficacy target is: a row exists ONLY
where the person overrode the derived ATC / name resolution, so it is a
decision and never a computation. Nothing recomputes it after a restore
because there is nothing to recompute it from.

The lab arm travels as a biomarker NAME rather than an id, the way a lab
result's cross-reference already does. A portable restore mints a fresh
catalogue id, and `Biomarker` is unique on `(userId, name)`, so the name
is the only end of the reference that survives the trip.

The obstacle was ordering, not machinery: the remap map already existed,
but the drugs are rebuilt several hundred lines before the analytes are.
The targets are collected against the id each drug actually got and
written in a second pass once the biomarkers exist.

The alternative was hoisting the biomarker restore above the medications,
and it loses on two counts. `biomarkerByName` and `restoredBiomarkerIds`
are read by the lab-result loop immediately below the block, so moving it
would separate a map from its only other consumer and leave a later edit
free to re-order them back with nothing noticing. And the dependency
would read backwards: a pinned target is a leaf of the medication tree,
and letting a leaf dictate where the clinical record gets rebuilt inverts
what the file is about. The second pass states the constraint where it
applies instead of hiding it in a line order.

A named analyte the restore did not put back is dropped and reported as
medicationTarget rather than written. `biomarkerId` is a real foreign
key, so a dangling value would fail the constraint and cost the whole
account over one override. Dropping beats nulling here because the
override IS the reference: a row with neither arm set is what the
resolver already reads as "no override", so keeping it would restore
something that means nothing while still holding the primary slot.

The round trip asserts the restored target points at the biomarker the
restore itself wrote, resolved from the database rather than remembered
from the fixture. Counting would have passed on a row whose biomarkerId
came back null, and nothing else would have complained: the resolver
falls back to deriving a target and the page still renders.
This commit is contained in:
Marc-André Bombeck committed 2026-08-22 11:49:52 +02:00
1 parent 14638a6660
commit 768320f3d3
14 files changed
+246 -9

No files matched your search

@@ -229,6 +229,9 @@ const COUNT_BACK: Record<
EnvironmentTravelLocation: (p, userId) =>
p.environmentTravelLocation.count({ where: { userId } }),
EcgRecording: (p, userId) => p.ecgRecording.count({ where: { userId } }),
// No own `userId` column — reached through the drug, like the schedules.
MedicationEfficacyTarget: (p, userId) =>
p.medicationEfficacyTarget.count({ where: { medication: { userId } } }),
};
/**
@@ -551,6 +554,17 @@ async function seedEveryTwoEndedModel(prisma: PrismaClient): Promise<void> {
takenAt: AT("2026-06-30T09:00:00.000Z"),
},
});
// What the drug above is FOR, pinned to the analyte just created. The two
// rows are seeded at opposite ends of this fixture on purpose: the drug is
// restored hundreds of lines before the analyte, so this pairing is what
// proves the second pass runs late enough to resolve the name.
await prisma.medicationEfficacyTarget.create({
data: {
medicationId: medication.id,
biomarkerId: biomarker.id,
primary: true,
},
});
await prisma.allergy.create({
data: { userId: OWNER_ID, substance: "Penicillin" },
});
@@ -1804,6 +1818,45 @@ describe("every model the plan claims two-ended survives a real restore", () =>
},
});
// The pinned target, and the analyte it points at.
//
// Counting says one override returned. It cannot say the override still
// MEANS anything: a restore that wrote the row with `biomarkerId` nulled
// returns a drug with no statement of what it was for, which is precisely
// what the register said the alternative cost, and nothing anywhere would
// complain — the resolver silently falls back to deriving a target and the
// page still renders.
//
// Both ends are resolved from the DATABASE rather than remembered from the
// fixture. The property the second pass owes is that the target points at
// the biomarker THIS restore wrote, which an id carried over from the
// seeding would not distinguish from a restore that copied a stale value.
const restoredBiomarker = await prisma.biomarker.findFirstOrThrow({
where: { userId: OWNER_ID },
});
const restoredMedication = await prisma.medication.findFirstOrThrow({
where: { userId: OWNER_ID },
});
const target = await prisma.medicationEfficacyTarget.findFirstOrThrow({
where: { medication: { userId: OWNER_ID } },
include: { biomarker: { select: { name: true, userId: true } } },
});
expect({
medicationId: target.medicationId,
biomarkerId: target.biomarkerId,
biomarkerName: target.biomarker?.name ?? null,
biomarkerOwner: target.biomarker?.userId ?? null,
measurementType: target.measurementType,
primary: target.primary,
}).toEqual({
medicationId: restoredMedication.id,
biomarkerId: restoredBiomarker.id,
biomarkerName: "Ferritin",
biomarkerOwner: OWNER_ID,
measurementType: null,
primary: true,
});
// The strip, read back column by column.
//
// Counting proves a recording returned. It cannot tell that recording from