* mdro(): infer base drug resistance from drug+inhibitor combination columns (#209)
When a base beta-lactam column (e.g., piperacillin/PIP) is absent but a
corresponding drug+inhibitor combination (e.g., piperacillin/tazobactam/TZP)
is present and resistant, resistance in the base drug is now correctly
inferred. This is clinically sound: resistance in a combination implies the
inhibitor provided no benefit, so the base drug is also resistant.
Susceptibility in a combination is NOT propagated to the base drug (the
inhibitor may be responsible for susceptibility), so only R values are
inferred; missing base drugs remain NA otherwise.
Implementation details:
- Uses AB_BETALACTAMS_WITH_INHIBITOR to identify all beta-lactam+inhibitor
combinations present in the user's data
- Derives base drug AB codes by stripping the "/inhibitor" part from names
- Creates synthetic proxy columns (.sir_proxy_<AB>) in x, set to "R" when
any matching combination is R, otherwise NA
- Proxy columns are added to cols_ab before drug variable assignment,
so all existing guideline logic benefits without any changes
- Multiple combos for the same base drug are OR-ed (any R → R)
- Adds internal ab_without_inhibitor() helper for the name->base mapping
- Verbose mode reports which combinations are used for inference
Bumps version: 3.0.1.9028 -> 3.0.1.9029
https://claude.ai/code/session_01Cp154UtssHg84bw38xiiTG
* Add sir.R/mic.R fixes and mdro() unit tests; bump to 3.0.1.9030
R/sir.R (line 571):
Guard purely numeric strings (e.g. "1", "8") from the Unicode letter
filter. Values matching the broad SIR regex but consisting only of digits
must not be stripped; add `x %unlike% "^[0-9+]$"` predicate.
R/mic.R (lines 220-222):
Preserve the letter 'e' during Unicode-letter removal so that MIC values
in scientific notation (e.g. "1e-3", "2.5e-2") survive the cleaning step.
- Line 220: [\\p{L}] → [^e\\P{L}] (remove all letters except 'e')
- Line 222: [^0-9.><= -]+ → [^0-9e.><= -]+ (allow 'e' in whitelist)
tests/testthat/test-mdro.R:
New tests for the drug+inhibitor inference added in the previous commit
(issue #209):
- TZP=R with no PIP column → PIP inferred R → MDRO class elevated
- TZP=S with no PIP column → proxy col is NA (not S) → class lower
- verbose mode emits "Inferring resistance" message
- AMC=R with no AMX column runs without error (Enterococcus faecium)
https://claude.ai/code/session_01Cp154UtssHg84bw38xiiTG
* Fix version to single bump (9029) and update CLAUDE.md versioning rules
CLAUDE.md: Rewrite the "Version and date bump" subsection to document that:
- Exactly ONE version bump is allowed per PR (PRs are squash-merged into one
commit on the default branch, so one commit = one version increment)
- The correct version is computed from git history:
currentversion="${currenttag}.$((commits_since_tag + 9001 + 1))"
with the +1 accounting for the PR's own squash commit not yet on the
default branch
- Fall back to incrementing DESCRIPTION's version by 1 if git describe fails
- The Date: field tracks the date of the *last* PR commit (updated each time)
DESCRIPTION / NEWS.md: Correct the version from 3.0.1.9030 back to 3.0.1.9029.
Two version bumps were made across two commits in this PR; since it will be
squash-merged as one commit only one bump is correct. Also update Date to
today (2026-03-07).
https://claude.ai/code/session_01Cp154UtssHg84bw38xiiTG
* Fix stats::setNames, test accessor bug, and version script verification
R/mdro.R:
Qualify setNames() as stats::setNames() in the drug+inhibitor inference
block to satisfy R CMD CHECK's global-function checks.
tests/testthat/test-mdro.R:
mdro() with verbose=FALSE returns an atomic ordered factor, not a
data.frame. Fix three test errors introduced in the previous commit:
- Line 320: result_no_pip$MDRO -> result_no_pip (factor, no $ accessor)
- Line 328: result_tzp_s$MDRO / result_no_pip$MDRO -> direct factor refs
- Line 347: expect_inherits(..., "data.frame") -> c("factor","ordered")
Also fix the comment on line 347 to match the actual return type.
Version: confirmed at 3.0.1.9029 (no further bump; one bump already made
this PR). git describe failed (no tags in dev environment) — fallback
applies. The +1 in CLAUDE.md's formula is correct for tagged repos:
currentcommit + 9001 + 1 = 27 + 9001 + 1 = 9029 ✓
https://claude.ai/code/session_01Cp154UtssHg84bw38xiiTG
* Fix unit tests: use mrgn guideline and expect_message() for proxy tests
Three failures corrected:
1. Classification tests (lines 321, 329): The EUCAST guideline for
P. aeruginosa already has OR logic (PIP OR TZP), so TZP=R alone
satisfies it regardless of whether the PIP proxy exists. Switch to
guideline="mrgn": the MRGN 4MRGN criterion for P. aeruginosa
requires PIP=R explicitly (lines 1488-1496 of mdro.R), with no TZP
fallback. Without the proxy: PIP missing -> not 4MRGN -> level 1.
With the proxy (TZP=R infers PIP=R): 4MRGN reached -> level 3.
The TZP=S case leaves proxy=NA, so PIP is still absent effectively
-> level 1, which is < level 3 as expected.
2. Verbose/message test (line 335): message_() routes through message()
to stderr, not cat() to stdout. expect_output() only captures stdout
so it always saw nothing. Fix: use expect_message() instead, and
remove the inner suppressMessages() that was swallowing the message
before expect_message() could capture it.
Also trim two stale lines left over from the old expect_output block.
https://claude.ai/code/session_01Cp154UtssHg84bw38xiiTG
---------
Co-authored-by: Claude <noreply@anthropic.com>