Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
807d13f
fix(medications): polish the interaction note text
claude Aug 13, 2026
91a164f
docs(ledger): record the interaction note polish review
claude Aug 13, 2026
4e1caeb
test(medications): preserve clinical text before hyphens
BigSimmo Aug 13, 2026
ef6afd2
test(medications): pin interaction link tap target
BigSimmo Aug 13, 2026
def6214
fix(medications): preserve unknown hyphenated clinical text
BigSimmo Aug 13, 2026
58240a8
style(medications): format interaction tap-target test
BigSimmo Aug 13, 2026
5bbd2a6
fix(medications): restore callout interaction tap target
BigSimmo Aug 13, 2026
34b6918
style(medications): normalise interaction test formatting
BigSimmo Aug 13, 2026
92bcdf4
fix: format medication interaction tests
BigSimmo Aug 13, 2026
dde5eae
feat(medications): make the interaction lexicon reviewable and give r…
claude Aug 13, 2026
8a664d5
Merge remote-tracking branch 'origin/claude/patient-interactions-drug…
claude Aug 13, 2026
498baf1
fix: normalise test file trailing newline
BigSimmo Aug 13, 2026
1020175
Merge main into medication interaction polish branch
BigSimmo Aug 13, 2026
5c51a7f
Merge remote-tracking branch 'origin/claude/patient-interactions-drug…
claude Aug 13, 2026
0f73858
style(medications): restore repo Prettier width on the interaction tests
claude Aug 13, 2026
fe303c0
style(medications): apply repository Prettier output
BigSimmo Aug 13, 2026
378dc1b
Merge remote-tracking branch 'origin/claude/patient-interactions-drug…
claude Aug 13, 2026
20e0172
docs(ledger): record the lexicon review sheet and reverse-note work
claude Aug 13, 2026
a736695
Merge branch 'main' into claude/patient-interactions-drug-alerts-3tztvw
BigSimmo Aug 13, 2026
bd9c988
Merge branch 'main' into claude/patient-interactions-drug-alerts-3tztvw
BigSimmo Aug 13, 2026
28800db
Merge branch 'main' into claude/patient-interactions-drug-alerts-3tztvw
BigSimmo Aug 13, 2026
79e89df
Merge branch 'main' into claude/patient-interactions-drug-alerts-3tztvw
BigSimmo Aug 13, 2026
b901d1a
Merge branch 'main' into claude/patient-interactions-drug-alerts-3tztvw
BigSimmo Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,601 changes: 1,051 additions & 550 deletions data/medication-interaction-index.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-08-13 | claude/patient-interactions-drug-alerts-3tztvw | 807d13f4ab2fbff8f292dafda7687cedf9079f2d | interaction note text polish (severity prefix, per-row severity chip, unclamped prose) | self-reviewed; shipped PR #1898 | verify:pr-local 9 stages green, failed:(none); 41 interaction tests pass; docs/adoption checks current; phone-chrome browser stages delegated to CI (#255 drift) |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-08-13 | claude/patient-interactions-drug-alerts-3tztvw | 378dc1b2c966d7765c086581245b86e4e810bc23 | medication interaction lexicon review sheet + reverse-direction note wording | ARB/carbapenem misclassification fixed; divergent duplicate Warfarin records reported; reverse-only alerts now carry their text | verify:pr-local 27/27 green (failed: none, not reached: none), 6326 unit tests |
115 changes: 115 additions & 0 deletions docs/medication-interaction-lexicon-review.md

Large diffs are not rendered by default.

41 changes: 38 additions & 3 deletions docs/samd-classification-medication-considerations.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,46 @@ Mitigations specific to the interaction surface:
- Colour is never the only channel: each verdict also carries an icon and a text
label.

**The lexicon needs its own clinical review, separately from the classification
question.** `src/lib/medication-interaction-lexicon.ts` decides which catalogue
drugs a phrase like "NSAIDs" or "CNS depressants" refers to, and that decision
drives every red and amber alert. It was assembled by pattern-matching the
corpus, not by a clinician, and has never been reviewed. `docs/medication-interaction-lexicon-review.md`
(generated by `npm run medications:lexicon-report`) expands every mapping to the
drugs it actually resolves to and carries a sign-off block; it is **UNREVIEWED**
until that block is filled in.

That report has already paid for itself twice:

1. It exposed `ARB` matching _C-**arb**-apenem_, which had put ertapenem and
meropenem in the angiotensin-receptor-blocker class across 16 CRITICAL/HIGH
rows. Fixed, and pinned by
`tests/medication-interaction-lexicon-coverage.test.ts`.
2. It exposed **two catalogue records both named "Warfarin"**
(`warfarin-vka`, `warfarin-anticoagulant`) that share **no interaction rows
at all** — three rows each, zero in common. Which record a clinician opens
therefore decides which warnings they see, and nothing on screen
distinguishes the two. This one is a **catalogue data defect, not a lexicon
fault**, so it is reported rather than silently patched: merging or
de-duplicating the records is a clinical content decision. It needs an owner.

Neither was found by review of the code; both fell out of rendering the mappings
in a form a human could read. That is a fair indication of what an hour of
clinical reading would still turn up.

Residual risk the reviewer should weigh: the lexicon is hand-curated, so a missed
term is a false negative. It is fail-safe by construction (unresolved → grey, not
green) but the resolution rate is not 100% — currently 400 of 523 rows resolve,
and `tests/medication-interaction-lexicon-coverage.test.ts` ratchets that figure
so it cannot silently regress.
green) but the resolution rate is not 100% — currently **355 of 523** interaction
rows are fully read, leaving 149 of the catalogue's medications holding at grey
rather than ever showing green. `tests/medication-interaction-lexicon-coverage.test.ts`
ratchets both that figure and the underlying drug-match count (417 rows) so
neither can silently regress.

Read the 355 carefully, because it went **down** from 400 deliberately. A row
naming an unenumerable mechanism ("CYP3A4 inhibitors (Clarithromycin,
Ketoconazole)") used to count as resolved once any one named drug matched,
which implied the whole mechanism class had been checked. It is now unresolved,
so more medications sit at grey. That is the safety direction, not a regression.

## Why this needs a classification decision

Expand Down
2 changes: 1 addition & 1 deletion docs/scripts-index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Scripts index

Curated map of `scripts/` (233 files) and the `package.json` script surface (242 entries),
Curated map of `scripts/` (234 files) and the `package.json` script surface (244 entries),
grouped by purpose. This is orientation, not an exhaustive per-file listing — the authoritative
command list is `package.json`, and `npm run docs:check-scripts` verifies every `npm run <x>`
referenced in docs resolves to a real script. `npm run docs:update` refreshes the exact counts above.
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@
"medications:seed": "node scripts/run-tsx.mjs scripts/seed-medication-records.ts",
"medications:interactions": "node scripts/run-tsx.mjs scripts/build-medication-interaction-index.ts",
"check:medication-interactions": "node scripts/run-tsx.mjs scripts/build-medication-interaction-index.ts --check",
"medications:lexicon-report": "node scripts/run-tsx.mjs scripts/build-medication-lexicon-report.ts",
"check:medication-lexicon-report": "node scripts/run-tsx.mjs scripts/build-medication-lexicon-report.ts --check",
"reindex": "node scripts/run-tsx.mjs scripts/reindex.ts",
"reindex:health": "node scripts/run-tsx.mjs scripts/reindex-health.ts",
"ingestion:autopilot": "node scripts/run-tsx.mjs scripts/ingestion-autopilot.ts",
Expand Down
16 changes: 16 additions & 0 deletions scripts/build-medication-interaction-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ type IndexRow = {
counterparties: string[];
termIds: string[];
resolved: boolean;
/**
* Verbatim `row.val`.
*
* Dropped from the artefact once, on the reasoning that every consumer already
* holds the `MedicationRecord` and could read the text back by `rowIndex`. That
* is true in one direction only. Interaction prose is not symmetric, so the
* evaluator also scans the PATIENT's medications for rows naming the viewed
* drug — and it has no record for those, which left a reverse-only match
* rendering a drug name and a severity chip with no explanation under it.
*
* The whole corpus is ~60 KB of prose (the 661 KB the artefact once weighed was
* repeated counterparty display names, not this), so carrying it is cheap
* relative to shipping an alert nobody can read.
*/
note: string;
};
type IndexEntry = { rows: IndexRow[]; unresolvedRowCount: number };
type InteractionIndex = {
Expand Down Expand Up @@ -200,6 +215,7 @@ function main(): void {
counterparties: Array.from(counterparties.keys()).sort(),
termIds: Array.from(termIds).sort(),
resolved,
note: value,
});
});
}
Expand Down
Loading
Loading