First batch of real calculator ports, routed through a new
shared/clinical/calculators.ts module that both the server tree and
the React client can import. Kept strictly to the simplest, closed-form
formulas — tables (Rosner BP, Fenton LMS, AAP 2022 bili, Bhutani, CDC
BMI) stay in the vanilla viewer until per-table vector files land.
shared/clinical/calculators.ts
Verbatim ports from public/js/calc-math.js:
• parseAgeMonths / formatAgeMonths — legacy age-string parser
• estimateWeightFromAgeMonths — APLS (Luscombe 2007) + Best Guess
(Tinning 2007) weight-for-age. Cross-checked line-by-line against
calc-math.js:14-39; identical branches, formulas, and roundTo
behavior.
• calculateMostellerBsa — sqrt(h·w/3600), Mosteller 1987.
• calculateWeightBasedDose — generic mg/kg with optional max cap
and mg/mL → mL conversion.
• calculateGcs — 1-15 sum with 8/12 severity thresholds.
shared/clinical/calculators.test.ts
Vitest unit coverage for each helper. Numeric assertions match the
legacy function outputs (3y APLS → 14 kg; 20 kg, 110 cm → 0.782 m²;
15 kg × 100 mg/kg capped at 500 mg, etc.). For these closed-form
formulas the hand-verified expected values are equivalent to a
vanilla-captured vector file — table-driven calculators still need
a JSON fixture before they port.
client/src/pages/Bedside.tsx
Top-level age-to-weight estimator now runs in React
(BedsideWeightEstimator). Formula dropdown switches between APLS
and Best Guess live; weight field accepts a manual override. The
15 clinical dosing sub-modules still fall through to the legacy
viewer via LegacyPanel.
client/src/pages/Calculators.tsx
BSA, Weight-Based Dosing, and GCS panels render real React forms
backed by the shared helpers. PILLS gain a `ported` flag so the
four covered panels (bsa, dose, gcs, + the already-shipped pills)
swap out of the legacy fallback while the others remain linked
out. Result blocks carry data-testid hooks for parity tests.
Config + dep hygiene picked up along the way
• client/tsconfig.app.json: @shared/* path alias, exclude test files
from the React tsc pass.
• tsconfig.json: exclude **/*.test.ts from the backend tsc pass.
• package.json: declare google-auth-library and jszip explicitly —
both were already required() in src/utils/ttsGoogle.ts and
src/routes/learningAI.ts but missing from dependencies, which
would break a clean `npm install`. Also adds engines: node >=20
and convenience verify / verify:full scripts.
• knip.json: quiet now-expected ignoreDependencies / ignoreBinaries
entries for marp-cli, tiptap, cap, etc.
• .gitignore: ignore the .codex CLI marker.
e2e/tests/bedside-react.spec.js
Adds the age→weight parity test: 3y APLS → 14 kg, 3y Best Guess →
16 kg, weight field mirrors the estimator output.
e2e/tests/calculators-react.spec.js
Adds BSA (20 kg, 110 cm → 0.782 m²), dose cap (15 kg × 100 mg/kg,
max 500 mg → 500 mg capped), and GCS (15 → 10 when motor drops
to 1) parity tests.
Client tsc -b + backend tsc --noEmit + vite build all clean.
Bundle 476.48 kB / 135.44 kB gzipped.
Co-Authored-By: Codex + vendor model Opus 4.7 (1M context) <noreply@anthropic.com>
Ships the /app/calculators page with the 10-pill sub-nav and flips
the sidebar Calculators link to available. All formula math stays
in the vanilla viewer for this commit.
client/src/pages/Calculators.tsx
PILLS array mirrors public/components/calculators.html exactly:
BP Percentile, BMI, Growth, Bilirubin, Vital Signs, BSA,
Weight-Based Dosing, Resus Meds, GCS, Equipment. Each pill carries
its canonical source (AAP 2017 Flynn / Fenton 2013 / AAP 2022
Kemper / Bhutani 1999 / Mosteller / PALS / …) so when a reader
opens the page they know which authoritative reference the numbers
trace back to.
Why no math in this commit — explicitly gated
The migration checkpoint has a specific rule for this tab:
"generate test vectors (JSON file with {inputs, expectedOutput}
tuples) by running the vanilla version with 20+ known cases. The
React port must match every vector byte-for-byte. An LLM will
sometimes 'simplify' a long array of numbers and silently break it
— don't let that happen." This applies in particular to:
• Rosner quantile splines in the BP percentile calc
• Fenton 2013 LMS preterm (210 validated cases)
• AAP 2022 bilirubin phototherapy + exchange (1190 validated cases)
• Bhutani nomogram risk zones
• APLS + Best Guess weight-for-age
Each formula gets its own commit once the vector file lands in
e2e/fixtures/ — this shell just makes the nav complete so users
can navigate to the tab in the React tree.
e2e/tests/calculators-react.spec.js — three smoke tests:
all 10 pills render by data-testid in the expected order, pill
click switches the active panel, and the legacy-viewer link is
present.
Client tsc -b + vite build clean. Bundle 460.19 kB / 131.43 kB gz.