// Personal targets the check engine trusts (H3). A target outside these ranges // is almost always a typing slip, 30 for 3.0, and would silence alerts: the // targets API refuses it, and the check ignores one saved before this rule // (and says so). Ranges are in the test's catalogue unit. Signed off with the // rules on 15 October 2026, unchanged since the review pack (src/domain/checks/signoff.ts). import { findLabTest, normalizeLabValue } from './catalog.js'; export interface TargetRange { min: number; max: number } export const PLAUSIBLE_TARGETS: Readonly> = { inr: { low: { min: 1.5, max: 3.5 }, high: { min: 2, max: 4.5 } }, }; /** * Results the check engine will act on (N16). One outside these limits is * almost always a typing slip (a potassium of 55 for 5.5) and is named as not * looking right instead of raising an alarm. In the catalogue unit. Signed * off with the rules on 15 October 2026, unchanged since the review pack. */ export const PLAUSIBLE_RESULTS: Readonly> = { potassium: { min: 1.5, max: 10 }, inr: { min: 0.5, max: 20 }, egfr: { min: 1, max: 200 }, }; /** Whether a result is outside the limits the check engine trusts. */ export function implausibleResult(code: string, value: number): boolean { const range = PLAUSIBLE_RESULTS[code]; return Boolean(range && (value < range.min || value > range.max)); } export type TargetProblem = | { kind: 'out_of_range'; field: 'low' | 'high'; min: number; max: number } | { kind: 'low_above_high'; field: 'low' }; /** Why a personal target can't be trusted, or null when it can (or the test has no ranges set). */ export function targetProblem(code: string, target: { low: number | null; high: number | null; unit?: string | null }): TargetProblem | null { const ranges = PLAUSIBLE_TARGETS[code]; if (!ranges) return null; const inCatalogueUnit = (value: number) => normalizeLabValue(code, value, target.unit ?? null)?.value ?? value; for (const field of ['low', 'high'] as const) { const value = target[field]; const range = ranges[field]; if (value === null || value === undefined || !range) continue; const comparable = inCatalogueUnit(value); if (comparable < range.min || comparable > range.max) return { kind: 'out_of_range', field, min: range.min, max: range.max }; } if (target.low !== null && target.high !== null && target.low > target.high) return { kind: 'low_above_high', field: 'low' }; return null; } /** "The INR target high must be between 2 and 4.5." */ export function targetProblemMessage(code: string, problem: TargetProblem): string { const name = findLabTest(code)?.name ?? code; return problem.kind === 'out_of_range' ? `The ${name} target ${problem.field} must be between ${problem.min} and ${problem.max}` : 'low must not be above high'; }