WorkWell Measure Studio is a TypeScript + Next.js monorepo for Total Worker Health (TWH) compliance operations (backend re-platformed off Java/Spring — #96 / ADR-008; JVM retired in #109 PR4). It combines measure authoring, deterministic CQL evaluation, case management, audit trails, admin tooling, and exportable evidence in one operational platform.
- Lifecycle-managed measures:
Draft -> Approved -> Active -> Deprecated - CQL compile + fixture validation gates before activation
- Scoped run pipeline:
ALL_PROGRAMS,MEASURE,SITE,EMPLOYEE,CASE - Case operations: outreach, assign/escalate, rerun-to-verify, timeline audit
- AI assist for CQL drafting and test fixture generation (never compliance decisions)
- MAT-compatible FHIR R4 export for measure portability
- Risk outlook analytics for upcoming exposure and repeat non-compliance patterns
- Built on MIE's
@mieweb/uicomponent library: dark mode + Enterprise Health brand with a runtime brand switcher, plus the DataVis NITRO data grid on the large operational/audit tables
- 2026-07-14 — pre-meeting closeout: evidence is DURABLE (#167 closed, ADR-030) + nightly DB
backups are live (#270). A
resolveBucketapp seam (the 9th inert-unless-configured seam,bucket-s3) routes evidence bytes to the managedworkwell-twh-evidenceS3 bucket (public-access-blocked, versioned, least-privilege IAM) — themieweb.jsoncbindings are literal JSON, so the durable backend is selected at app level exactly like theDATABASE_URLstore override.backup-neon-nightly.ymldumps theworkwell_spikeschema to the same bucket nightly (30-day lifecycle) — material because the live Neon PITR window is the Free-plan-capped six hours (API-verified; the remaining owner decision is a plan upgrade). The DR runbook's §6 drill was executed on a live Neon branch (delete → PITR restore → rows returned). Also: #268 closed (shipped by PR #284), the decommissioned Vercel preview project deleted, stalephase1-spike/skeleton strings removed fromworker.ts, and doc drift reconciled (catalog 63; live scale tenant = the N=5000 real-eval, 72,100 All-Systems outcomes). - 2026-07-13 — independence sprint (PRs #286, #288, #289 merged). WebChart's
integration contract turned out to be publicly documented and live-verifiable: FHIR R4 + US Core 7
- SMART Backend Services, with a public sandbox (
fhirr4sandbox.webchartnow.com). The E12 PR-2c transport was rebuilt to that verified contract (RS384private_key_jwtvia WebCrypto, per-resource?patient=composition — no$everything; ADR-028), most #254 questions now carry provisional confirm/correct answers, the sandbox probe sharpened the remaining ask to "register us a backend-services client (JWKS attached)", and the live CMS122 fidelity diff was verified runningmode:"literal"in production (fqm-execution over the official MADiE artifact; the VSAC OIDs were imported 2026-07-05). Research record:docs/INTEGRATION_RESEARCH_2026-07-13.md. New: #287 (calculation-level cross-system credit).
- SMART Backend Services, with a public sandbox (
- Immunization forecasting is real — the ICE stub is now a live adapter (ADR-029).
iceForecasterhad been inert since E6 (#76); ICE turned out to be self-hostable today (HLN's ACIP-maintainedhlnconsulting/iceimage), sorealIceForecasternow speaks its OpenCDS DSS contract through a dependency-free vMR codec — selected byWORKWELL_IMMZ_ICE_BASE_URLalone (a self-hosted sidecar has no API key), with a whole-forecast fallback to the simulated forecaster on any failure, and an injectable dose-history source (the E12/WebChart drop-in). Verified against a real container (5 live tests that self-skip without the env var); the demo stack staysice=offand byte-identical. Forecasts remain advisory — CQL is still the sole compliance authority (ADR-008/ADR-012). Answers #254 Q D18 ourselves. Suite 1270: 1265 pass / 0 fail / 5 skip. No schema, no new deps. - Design/ops docs (#263 delta-eval, #287 cross-system credit, #270 backup/DR). Each surfaced
something that changes the shape of the work: a delta run that skipped outcome rows would silently
break every read model (and the saving is ~21%, not ~99%, without status-boundary caching); Doug's
"compliant anywhere" hides two lenses, only one of which preserves
All = Σ tenants; and the live Neon PITR window is six hours, with no second line of defence — one bucket unblocks both #167 and a nightly DB dump. All owner-gated: no code, no DDL. - Roadmap 2026-07-09 — PoC → WebChart integration (M1/M2/M3). M1 engineering closed 2026-07-10
(PRs #271–#279 on
main): mock WebChart HTTP transport, worker pool, tiered evidence, fqm literal CMS122 fidelity (#258 / ADR-026), full dev-DB fixtures, seam inventory, production-readiness memo, N=5000 real-eval proof. PR #280 MERGED — production-faithful CMS122v14 + CMS125v14 eCQI subsets (age/visit/VSAC/GMI/Oct-1 mammo window; dual-coded synthetic). Remaining M1 owner step: #254 — senddocs/MIE_INTEGRATION_QUESTIONS_2026-07-09.md(unblocks M2: #262 live transport, #263 delta-eval, #187 identity). Strategy:docs/ROADMAP_2026-07-09.md. eCQM honesty: only CMS122 + CMS125 are runnable Active (both faithful-subset production CQL as of #280); catalog metadata for 49 CMS IDs is eCQI-current (2026/v14); 47 Drafts not evaluated — seedocs/MEASURES.md→ "eCQM accuracy posture". - Production-readiness memo (#261 — docs only).
docs/PRODUCTION_READINESS_2026-07.mdnames the hard rule (the demo stack never receives PHI), maps existing controls vs gaps, and tracks M3 issues (#167, #264, #265, #267–#270, #168). PHI/auth/tenancy decisions wait on MIE answers indocs/MIE_INTEGRATION_QUESTIONS_2026-07-09.md. - Option A at scale — real batch live-evaluation of the
mhn(~120k) tenant (PR #252 — merged 2026-07-08). The population-scale tenant's outcomes are now produced by real batch CQL evaluation (batchEvaluateScalePopulation,backend-ts/src/run/batch-evaluate-scale.ts) instead of a fabricated compliance distribution — subject-major, bounded-memory, whole-batch resumable, per-subject error-isolated (failure ⇒ MISSING_DATA + error evidence), auditedSCALE_POPULATION_EVALUATED. The defaultwebChartRealisticGeneratoremits real LOINC/CVX/CPT codes through the WebChart terminology crosswalk (13/14 measures;hazwoperpasses through), exercising the real adapter at scale.pnpm seed:scale --mode evaluateis now the default (--mode fabricatedkeeps the legacy instant path one more release;--trim-evidencefor a large run). Evaluate mode refuses over legacy fabricatedseed:scaleruns (distinguished by arequestedScope.batchEvaluatedmarker) — so a DB with the old fabricated seed (incl. live Neon) must be rolled back first (DEPLOY.md). Themhn|Lxx|Pxx|nsubject_idencoding +aggregateScaleRun(and thus the whole rollup/hierarchy read path) are unchanged — only the outcomes' provenance changed. Descriptive only (ADR-008/ADR-020); no schema, no new deps; same rollback SQL. Reviewed (code-reviewer skill + Codex low + Codex gpt-5.5 high); full suite 1057 pass / 1 pg-skip / 0 fail. Seedocs/JOURNAL.md. - E9 (#78) — measure-execution
MeasureExecutorseam; the CQL→SQL fork decided on our own (ADR-025). The charter's biggest architectural fork (Doug's Q2) resolved without waiting: measure execution is now pluggable behind one port (backend-ts/src/engine/measure-executor.ts) that extendsEvaluateMeasureBinding, so an executor drops intoevaluateBundle/evaluateBatchwith no new plumbing.fhirNativeExecutoris the default + correctness oracle (delegates to the existing CQL→ELM engine — no second evaluation path, parity-tested);sqlPushdownExecutoris an inert stub (Option B / CQL→SQL is research-grade, not built — constructs but rejects on use, mirroring the inertwebChartDataSource);resolveMeasureExecutor(env)selects config-driven (SQL only on an explicitWORKWELL_MEASURE_EXECUTOR=sql-pushdownopt-in, so the deployed default is byte-identical to today). Any future SQL executor must pass golden parity vs the FHIR-native oracle, per measure, before it serves. Descriptive only (ADR-008); no schema, no new deps, no engine change. ADR-014 superseded; ADR-017's parked "opt-in second executor" is now the concrete seam. 1017 backend tests (1017 pass / 1 pg-skip). Seedocs/JOURNAL.md. - 2026 terminology & standards currency sweep (
docs/TERMINOLOGY_AUDIT_2026-07-08.md). A three-way verification — our implementation vs MIE's WebChart dev DB vs the current 2026 authorities (CMS eCQI, CDC CVX, LOINC, VSAC, AMA CPT, eCFR) — confirmed everything load-bearing is correct: all 49 CMS catalog versions/MIPS IDs (v14 = 2026), all OSHA CFR citations, all runnable LOINC/CPT codes. Fixed the one defect class, vaccine-CVX currency on the WebChart crosswalk: the influenza set expanded from141/140-only to the full active seasonal CVX set (VSAC "Influenza Vaccine" OID2.16.840.1.113883.3.526.3.1254); the inactive Td code139supplemented with active09/113/196; MMRV94now counts toward varicella; deleted HCPCSG0202marked read-only. Additive to the WebChart read path only — synthetic outcomes unchanged (the synthetic CQL matchesurn:workwell:*codes, not CVX). Descriptive only (ADR-008); no schema, no new deps. Seedocs/JOURNAL.md. - Foreign-data correctness pre-E12 — AI prompt fencing (L14) + out-of-population signal (L17) (PR #250 — merged). The two Fable "pre-E12" items that become wrong answers / attack surface once real WebChart data flows in. L14:
explainCaseno longer interpolates raw evidence JSON into the model prompt —buildExplainUserPromptwraps it in per-request nonce'dBEGIN/END EVIDENCE JSONmarkers labelled untrusted-data-not-instructions and size-caps it (8000 chars), a prompt-injection guard for the day E12 feeds real WebChart-derived strings (AI_GUARDRAILS §2.2). L17: an additiveinInitialPopulation?: booleanonMeasureOutcome(read from the CQL "Initial Population" define) distinguishes an out-of-program subject from an enrolled-but-no-data MISSING_DATA on the CLI/ingress path (ARCHITECTURE §7). Descriptive only (ADR-008); no schema, no new deps. Seedocs/JOURNAL.md. - WebChart dev-DB evaluation proof — offline (#246; PRs #247/#248 + demo CLI). Proves the WebChart→FHIR adapter end-to-end on MIE's real seeded WebChart dev DB (
ghcr.io/mieweb/dev-wcdb, ~56 patients) with no live API and no MariaDB driver, while the live HTTP transport (E12 PR-2c) stays deferred behind itsWebChartClientseam. PR-1 an OH enrollment roster (stampEnrollment) that closes the enrollment gap (WebChart carries nourn:workwell:vs:*program-membership Condition); PR-2 a driver-free dev-only export (docker exec … mysql, JSON serialized in Node) → committed WebChart-shaped FHIR fixtures + a deterministic per-patient e2e proof, and the crosswalk firmed to MIE's actual codes (LDL LOINC2089-1, systolic BP8480-6); PR-3pnpm evaluate:webchart-devdbprints a per-measure outcome table (28 real non-MISSING_DATA outcomes over the whitelist). Descriptive only (ADR-008); no schema, no new deps. Seedocs/WEBCHART_FHIR_MAPPING.md§8.1. - Backlog sweep — #233 perf residual + E14 GMI numerator + UX-3/7/13/14/15 (PRs #244 + #245 — merged). Backend (#244): the latest-population-run-per-measure reduction is pushed into SQL (
listLatestPopulationOutcomes, ~20k → ~2,100 rows shipped, output byte-identical) and the CMS122 official-subset numerator now takes the most-recent of HbA1c OR GMI (LOINC 97506-0), closing Fable L15. Frontend UX (#245): UX-7 styled evidence dropzone + ephemeral-storage note; UX-14 passive metadata-chip tier (DeliveryChip); UX-15 Studio version-actions grouped into an accessible disclosure; UX-3 optimistic panel caching + a ">3s / Crunching ~1.68M outcomes" hint on/compliance+/programs/hierarchy; UX-13 "Global" label on the header selectors (the fuller per-page filter-bar refactor deferred as a design call). Descriptive/presentational (ADR-008); no schema, no new deps. Seedocs/JOURNAL.md. - E14 PR-3 — real CMS122 execution outcome diff + live VSAC on-ramp (PRs #242 + #243 — merged; ADR-023/ADR-024).
GET /api/measures/cms122/fidelity/diffis now a real, subject-by-subject execution diff: for each subject in the latest cms122 run it builds → harness-locally VSAC-enriches → evaluates both WorkWell's authoredcms122and an official-subset CMS122 measure fresh → diffs, attributing each divergence to the first differing official gate. #242 landed the live VSAC (NLM UMLS) resolver behind theValueSetResolverport (CompositeValueSetResolver, key-gated inert-unless-configured; the owner-runpnpm resolve-valuesetsimport CLI). A compile-feasibility spike proved the literal multi-library QICore CQL un-compilable under the pinned JVM-free translator, so the deliverable is a faithful official-subset (measures/cms122_official.cql); revisit on a stable multi-model translator release (ADR-024). Descriptive only (ADR-008); no schema, no new deps. Seedocs/JOURNAL.md. - UX-11 — compliance roster mobile card layout (PR #241 — merged). On phones (below
md) the/complianceroster renders as per-employee cards (RosterMobileCards: name link + tenant · site · role + a<dl>of measure →ComplianceChip) instead of a wide table that showed ~1.5 columns per screen; the table stays atmd+. CSS-only responsive (display:nonekeeps the hidden layout out of the a11y tree). Same data/filters/paging; chips verbatim from the read model (ADR-008). No backend, no schema, no new deps. Seedocs/JOURNAL.md. - UX-8 — program-card trends onto monthly
quality_snapshots(PR #240 — merged). The/programsper-card trend flat-lined under the daily scheduled runs; rewired it to the monthly E16 snapshot series (opt-in via?granularity=month, so only the card switches while the measure page stays per-run), scoped by the tenant/site filters with a per-run fallback when a scope has <2 months (or a partial-month range). Newest-first,compliant/totalrate matching the headline. AdditiveProgramTrendPoint.period; frontendtrendMeta. No schema, no new endpoint, no new deps. Seedocs/JOURNAL.md. - perf(#233) — roster + hierarchy latency ~5–6× faster warm (PRs #238 + #239 — merged). The shared
listOutcomesWithRunwas seq-scanning all ~1.7Moutcomesrows to exclude the scale tenant; rewrote it torun_id = ANY(<live run ids>)(index scan, 3,242ms → 41ms live) + memoizedaggregateScaleRun(immutable scale runs). The roster additionally caches its derived cells per immutable run (skips the ~1.3MBevidence_jsonreload), guarded by a/evaluate-on-terminal-run 409. Live warm: roster ~1.0s, hierarchy ~1.1s (from 5–13s). No schema, no new deps. Seedocs/JOURNAL.md. - WCAG 2.2 AA audit + remediation (PR #237 — merged). A code-level pass over the whole
frontend/surface (5 parallel auditors): 0 critical, 1 High, ~40 mechanical. Fixed the High (keyboard-inaccessible OSHA-reference combobox → a real ARIA combobox) plus anaria-live/role=alertsweep (~19 sites), a contrast-token sweep (~15 sites), focus rings, target sizes, and semantics (admin ARIA tabs, table-row semantics, mobile<h1>). No new deps. Seedocs/WCAG_AUDIT_2026-07-03.md. - UI/UX Fable pass-3 + a11y (PRs #235 + #236 — merged). Role-aware papercuts, on-demand (un-billed) AI run-insight, UUID-linking (
CopyableId), a unifiedAccessDenied, and the a11y semantics groundwork the WCAG pass built on. Seedocs/JOURNAL.md. - Fable correctness/security/scale hardening pass (PRs #226–#232 — merged). The population-run pipeline is now fully audited (
RUN_COMPLETED+ per-case events), case upsert is state-aware (preserves IN_PROGRESS, respects human closures), cycle-rollover closes stale-period cases, bounded run-detail reads at 120k scale, spike-store indexes, UTC-stable evidence dates, and a batch of frontend mediums. Seedocs/JOURNAL.md. - E12 PR-2b — WebChart→FHIR adapter core (PR #234 — merged). The transport-agnostic adapter (
backend-ts/src/engine/ingress/webchart/): terminology reconciliation (real LOINC/CVX/CPT → the synthetic measure-event codings), bundle normalization, and an injectableWebChartClientseam (the HTTP transport is deferred until the MIE API contract). Descriptive only (ADR-008/ADR-017); no schema, no new deps. Seedocs/WEBCHART_FHIR_MAPPING.md. - E15 PR-2 + merge-picker — identity reconcile write path (PRs #224 + #225 — merged; E15 complete). The confirm/unlink half of cross-system identity (ADR-022). The first E15 schema — an owner-approved
person_linkstable (floor + ceiling,workwell_spike; self-creating DDL) recording human-confirmed CONFIRMED/BROKEN assertions between two source records (pair-normalized;PersonLinkStoreport).resolvePeopleis override-aware (union-find).POST /api/identity/people/:personId/reconcile— CASE_MANAGER/ADMIN-gated + audited (IDENTITY_LINK_CONFIRMED/IDENTITY_LINK_BROKEN); frontend adds CM/ADMIN unlink + a CONFIRM_LINK merge-picker. Descriptive only (ADR-008); reversible (DELETE FROM person_links; cleared on demo reset). No new deps. Seedocs/JOURNAL.md. - E15 PR-1 — cross-system identity (PR #223 — merged). A pure read-time person-identity layer (
backend-ts/src/identity/, ADR-022): resolves one person across ≥1 WebChart systems by a deterministic shared-identifier match key (the EMPI seam), surfaces DUPLICATE candidates (same person in >1 system), and builds a merged, system-tagged compliance timeline with a mobility annotation (history follows a person across a move).GET /api/identity/{people,people/:id,duplicates}(authenticated read-only) + a new/peopleroute (DUPLICATE badge + search + unified person view + mobility banner). Cross-system people are modeled in the synthetic directory with no schema and no count change (shared syntheticnationalId/dateOfBirthon two existing twh↔ihn pairs); E13 reconciliation (All = Σ tenants) is preserved by a guard test. Match-don't-auto-merge — the reconcile write path is E15 PR-2 (owner-gated); real WebChart sources are PR-3 (E12 seam). Descriptive only (ADR-008); no new deps. 831 backend tests (830 pass / 1 pg-skip); frontend lint + build green. Seedocs/JOURNAL.md. - E16 PR-2 + PR-3 — quality-over-time history API, backfill CLI, and UI (PR #222 — merged; E16 complete). On top of PR-1's snapshot store (#221):
GET /api/quality/history(bounded snapshot time-series read,YYYY-MM-validated, authenticated read-only);pnpm seed:quality-history [--months 12] [--as-of YYYY-MM]— materializes real evaluated snapshots for past months (superseding the syntheticseed:trend-historyfor the quality trend), audited, idempotent + resumable, reversible; and a "Quality over time (source of truth)" card on/programs/[measureId]with a scope selector, as-of month picker, "compliance on month M" numerator/denominator KPI, and a snapshot-backed chart (+ChartDataTablealternative). Descriptive only (ADR-008/ADR-021); no schema change (reuses PR-1'squality_snapshots), no new deps. 817 backend tests (816 pass / 1 pg-skip); frontend lint + build + 107 vitest green. Seedocs/JOURNAL.md. - WCAG chart accessible-alternatives (PR #218). Completes the chart half of the a11y pass deferred from PR #210: a shared
ChartDataTable(frontend/components/chart-data-table.tsx) renders a screen-reader-only captioned data table beside each of the 3 dashboard Recharts charts (nowaria-hidden), so assistive tech gets the underlying numbers instead of an unlabeled graphic (WCAG 1.1.1). Recharts v3's default-focusable keyboard layers are disabled underaria-hidden(accessibilityLayer={false}+ PierootTabIndex={-1}) to avoid anaria-hidden-focusregression. 6 unit tests; lint + 105 vitest + build green. No schema, no new deps. Bundles the E15 (#187) and E9 (#78) roadmap design specs (drafts) and closes the E11 epic (#183). Seedocs/JOURNAL.md. - E14 PR-2 — criteria-impact outcome diff (PR #217 — merged + deployed).
GET /api/measures/:id/fidelity/diff— a pure criteria-impact analysis (computeOutcomeDiff,backend-ts/src/standards/outcome-diff.ts) showing criterion-by-criterion how many subjects from the latest CMS122 population run would have different outcomes if the official eCQM criteria were applied. Structural-first (ADR-018); full CQL execution diff deferred to PR-3 (blocked on VSAC credentials). Descriptive only (ADR-008); no schema, no new deps. 785 tests pass. Seedocs/JOURNAL.md. - E13 PR-3 — scheduled cron recompute (PR #216 — merged + deployed; closes E13). Wires the previously-inert
/api/admin/schedulerto fire real auditedALL_PROGRAMSruns on a 24-hour interval. In-processsetInterval(5-min tick × 23.5h debounce), opt-in viaWORKWELL_SCHEDULER_ENABLED=true.SCHEDULER_RUN_TRIGGEREDaudit event written beforeplanManualRun(hard rule).triggerType:"SCHEDULED"onGET /api/runs. No schema, no new deps. Seedocs/JOURNAL.md. - E13 PR-2 — population-scale tenant (PR #215 — merged + deployed). Proves the multi-tenant rollup scales to ~120k subjects (
mhn/ "MetroHealth Network"): generated outcomes with encodedsubject_id(mhn|Lxx|Pxx|n), SQLGROUP BYaggregation (aggregateScaleRun) — O(providers) rows, never the 120k per-subject rows. On-demand seed viapnpm seed:scale, idempotent, reversible; provider-leaf rollup (scale-rollup.ts). 4 Codex P2 fixes included (site filter, date window, React key dedup, partial-seed idempotency). No DDL, no new deps; ADR-020. Owner step done:pnpm seed:scale --subjects 120000 --as-of 2026-06-26— 1.68M outcomes seeded on Neon; live All Systems = 1,682,100. Seedocs/JOURNAL.md. - E13 PR-1 — multi-tenant (multi-system) rollup (PR #214 — merged + deployed). A tenant/system dimension above the existing hierarchy, modeled read-time in the synthetic directory (ADR-019): two WebChart systems (
twh100 employees +ihnIndus Hospital Network 50 employees); a single reconciling "All Systems" root;?tenant=scoping everywhere;GET /api/tenants; System<select>on/programs,/compliance,/programs/hierarchy. No schema, no new deps. Seedocs/JOURNAL.md. - E14 PR-1 — standards fidelity diff (PR #212 — merged + deployed). A
backend-ts/src/standards/module that diffs WorkWell's authored eCQM measure against the official spec: a vendored, sourced CMS122v14 reference (official population criteria + ~21 VSAC value-set OIDs + provenance, verified against the official QDM HTML) +computeFidelity→GET /api/measures/:id/fidelity(COVERED/SIMPLIFIED/OMITTED per criterion + value-set fidelity), plus ajurisdictionmetadata field and a country-aware design memo. Structural-first (ADR-018); official-CQL execution/outcome diff deferred to PR-2. Descriptive only (ADR-008); no schema, no new deps. Seedocs/JOURNAL.md. - WCAG accessibility pass (PR #210 — merged + deployed). Keyboard-accessible activation, Studio ARIA tab pattern (roving tabIndex + arrow nav),
aria-livestatus announcements, table-row semantics, stable list keys. Verify-first (the app was already largely accessible). Chart accessible-alternatives split to a follow-up (now done in PR #218). No new deps. Seedocs/JOURNAL.md. - QA follow-ups closeout (PR #209 — merged + deployed). M1 measure-aware next-action labels (was defaulting non-OSHA measures to "audiogram"); H2 an inert SendGrid email seam (
resolveEmailService(env), simulated default) so code matches the docs; evidence persistence documented as aCloudBucket-port deploy-config step. No schema, no new deps. Plus a deploy-reliability fix (PR #211): the MIE deploy script polls container status untilrunninginstead of racing startup. Seedocs/JOURNAL.md. - E12 PR-1 — pluggable data ingress (PR #208 — merged + deployed). A
backend-ts/src/engine/ingress/module above the unchanged engine: DB-lessevaluateBundle/evaluateBatch(JSON-bucket, per-item error isolation), aPatientDataSourceport +resolveDataSource(env)selection, an inertwebChartDataSourcestub, CLI reuse. Records the E9 FHIR-native-first fork (ADR-017). No schema, no new deps. PR-2 (real WebChart/MariaDB→FHIR adapter) is parked pending MIE's schema. Seedocs/JOURNAL.md. - E11.3 PR-2 — Configure Groups UI (PR #206 — merged + deployed; closes E11). An ADMIN
/admin → Groupseditor (rule builder + applicable measures + INCLUDE/EXCLUDE overrides + live membership preview) + aPOST /api/segments/previewdry-run endpoint + the rosterNOT_APPLICABLEchip and?segment=filter. ADMIN-gated writes; applicability gates case-creation + display only — never compliance (ADR-008/ADR-016). No schema, no new deps. With this, all of E11 is merged + live. Seedocs/JOURNAL.md. - E11.3 PR-1 — risk-group SEGMENTS backend (PR #205 — merged + deployed + verified live). A cohort (role/site predicate rule + per-employee INCLUDE/EXCLUDE overrides) → an applicable measure-id rule-set, persisted in 3 owner-gated tables behind a
SegmentStoreport (floor + ceiling). A single pure applicability engine gates the roster (aNOT_APPLICABLEoverlay + a?segment=filter) and run-pipeline case creation — never compliance (ADR-016; CQLOutcome Statusstays authoritative). ADMIN-gated audited/api/segmentsCRUD; 3 enabled demo cohorts (the overlay is live on the demo). Reversible: zero enabled segments ⇒ everything applicable. No new deps. Seedocs/JOURNAL.md. - Live Hep B repointed to Heplisav-vs-traditional (E11.2c PR-2, #204 — merged + deployed). The live
hepatitis_b_vaccination_seriesmeasure now uses the E11.2c multi-alternative codegen: Heplisav-B (2 doses CVX 189, ≥28d) OR traditional (3 doses CVX 08/43/44/45, ACIP min intervals 28/56d). The synthetic dose model picks one alternative per employee (stable hash) and stamps its CVX/count/spacing; advisory consumers (forecaster, order-catalog, catalog spec) follow. No schema change, no new deps; reversible by reverting the PR. CQLOutcome Statusstays the sole compliance authority (ADR-008/ADR-015). Seedocs/JOURNAL.md. - Multi-alternative-series codegen + Rule Builder UI (E11.2c PR-1, PR #203 — merged). The CQL rule→codegen supports an OR of alternative dose series with multi-CVX code sets + per-alternative ACIP minimum dose intervals, plus a Rule Builder "Alternative series (multi-brand)" authoring sub-form. Capability only — no live measure change; additive + back-compatible (absent
alternatives⇒ identical to E11.1), no schema, no new deps. CQL stays canonical (ADR-015);Outcome Statusis the sole compliance authority (ADR-008). - QA/UX hardening pass 2 (PR #181) — merged + deployed. Role-aware nav + action gating, programs/case-detail/runs/admin UX + perf fixes, a new
/orderspage (E7 UI), a global run-progress indicator, a conservative API GET cache, an accessibility pass, and bounded audit-ledger queries — no schema change, no new deps. Seedocs/JOURNAL.md. - All planned sprints (0–7) are implemented and merged to
main; Sprint 7 issues#47–#51are closed. - Sprint 8 scoped-run parity, the 8-way CI test-sharding speedup (~3.8×), the MIE Container Manager v1 API deploy migration, and the
@mieweb/uifrontend migration (PR #68) are all merged. - Strategic roadmap underway (tracked as GitHub issues
#71–#78): the engine is being decomposed into reusable ports/adapters so real EHR/FHIR data can plug in later. E1 — reusable measure engine ports/adapters (PR #95, epic #71) is merged. - De-Java re-platform — DONE; JVM retired (issue
#96, ADR-008): the backend was ported off Java/Spring Boot onto a TypeScript /@mieweb/cloudstack (backend-ts/), strangler-fig behind the unchanged Next.js fetch contract, CQL Path C (build-time CQL→ELM, JVM-free Node execution). As of the #109 deploy cutover,https://twh.os.mieweb.orgis served by the TypeScript backend (https://twh-api-ts.os.mieweb.org) on the existing Neon Postgres via thePg*Storeceiling, and the Java backend has been retired (backend/deleted in PR4). The full ported surface is live: runs (incl. ALL_PROGRAMS/SITE async viactx.waitUntil), cases, measures (catalog + detail + create/lifecycle + Spec/CQL/Tests authoring), programs, exports, admin (reads + toggles + write CRUD), AI surfaces, the 13 MCP tools, auditor packets, MAT export, measure analytics, and value-set governance. ~427backend-tstests green. Cutover path: engine + JVM-free ELM Explorer (#106), auth/CORS (#105), SQLite-floor + Postgres-ceiling storage (#104), the Phase-4/4b API strangler (#108), then container/image (#155) → store-selection seam (#156) → shadow deploy + Neon-pooler fix (#157/#158) → blue-green flip (#159). #109 PR4 retired the JVM:backend/deleted, the Java build/deploy jobs + the shadow workflow removed,backend-tsCI-gated (floor + Pg ceiling) as the sole backend, and a self-heal reconciler (reconcile-twh-mieweb.yml) recreates a down container from:latestindependently of Proxmoxonboot. (The evidence-upload-is-ephemeral limitation noted here historically was closed 2026-07-14 — #167/ADR-030.) Plan + resume guide:docs/superpowers/plans/2026-06-15-issue-109-deploy-cutover.md; narrative indocs/JOURNAL.md. - Default branch:
main(feature branches deleted after merge).
- Live frontend:
https://twh.os.mieweb.org - Live backend API:
https://twh-api-ts.os.mieweb.org— the TypeScript backend (backend-ts/), the sole backend (Java retired in #109 PR4)
As of the #109 cutover the frontend is served by the TypeScript backend; the Java/Spring backend has been retired (
backend/deleted). The earlier Vercel + Fly.io public-preview stack (workwell-measure-studio.vercel.app,workwell-measure-studio-api.fly.dev) is decommissioned. MIE TWH is the sole live deployment.
- Backend: TypeScript on
@mieweb/cloud(backend-ts/) — a Cloudflare-style worker on a long-lived Node host, JVM-free CQL (build-time CQL→ELM), Neon PostgreSQL 16 (Pg*Storeceiling; SQLite floor for tests/local) - Frontend: Next.js 16 App Router, TypeScript, Tailwind 4,
@mieweb/ui(dark mode + Enterprise Health brand + runtime brand switcher), Monaco - CQL/FHIR: build-time CQL→ELM (JVM-free)
- Infra: MIE Create-a-Container (primary) + a self-heal reconciler, Neon, GitHub Actions
backend-ts/API worker, CQL→ELM engine, caseflow, exports, security, MCP, store adapters (SQLite floor + Postgres ceiling)frontend/dashboard, Studio, admin, login, UX surfacesdocs/architecture, data model, deploy, runbooks, sprint and journal historye2e/Playwright tests
- Node.js 20+
- pnpm (via Corepack) for the backend; npm for the frontend
cd backend-ts
pnpm install
pnpm typecheck
pnpm test
pnpm devcd frontend
npm install
npm run lint
npm run build
npm run devMeasure bindings are declarative YAML files (backend-ts/measures/*.yaml, one per runnable measure,
sibling to its CQL). A packaged headless CLI answers compliance for an arbitrary FHIR R4 patient
bundle with no server and no database — run it from backend-ts/:
pnpm evaluate --patient ./patient-bundle.json --measure audiogram --date 2026-06-12 --pretty--measure is a registry id (audiogram, hazwoper, tb_surveillance, flu_vaccine, hypertension,
diabetes_hba1c, obesity_bmi, cholesterol_ldl, cms125, cms122, adult_immunization); --date defaults to today.
It's a thin shell (backend-ts/src/engine/cli/) over the same CqlExecutionEngine the run pipeline uses.
Output is the MeasureOutcome JSON:
pnpm seed:trend-history backfills backdated weekly COMPLETED runs per runnable measure so the
/programs + /programs/[measureId] trend charts show realistic variation instead of flat lines —
on-demand, idempotent, not auto-run on deploy (backend-ts/src/run/cli/):
pnpm seed:trend-history --weeks 12 --as-of 2026-06-21Seeded runs are labeled SEED (real operator runs stay MANUAL), are anchored strictly before each
measure's latest real run so the programs overview is never affected, and add no schema. See
Deploy Guide for the reversible rollback SQL.
pnpm seed:scale populates the mhn "MetroHealth Network" ~120k-subject tenant so the
/programs/hierarchy rollup + /programs KPIs aggregate a real population-scale system (E13 PR-2).
The subjects are generated demo data (not live-evaluated) living only as outcomes rows whose
subject_id encodes the hierarchy (mhn|Lxx|Pxx|n) — no schema; the rollup aggregates them in SQL
(GROUP BY), so app memory never holds the 120k rows. On-demand, idempotent, not auto-run on
deploy (backend-ts/src/run/cli/):
pnpm seed:scale --subjects 120000 --as-of 2026-06-26Reversible (delete the seed:scale runs+outcomes — see the Deploy Guide).
{
"subjectId" : "demo-patient-1",
"measure" : "Audiogram",
"outcome" : "COMPLIANT",
"evidence" : { "expressionResults" : [ { "define" : "Days Since Last Audiogram", "result" : 100 }, "..." ] }
}The same DB-less evaluation is also a library entry (E12 PR-1, #184) — evaluateBundle(bundle, measureId)
for a single JSON/FHIR object and evaluateBatch(bundles, measureId) for a "bucket" of them (per-item error
isolation), both from backend-ts/src/engine/ingress, with no server or DB.
# backend
cd backend-ts
pnpm typecheck
pnpm test
# frontend
cd ../frontend
npm run lint
npm run test
npm run build/complianceIndividual Compliance Status roster grid (every employee × the selected panel's measures; chip + method per cell)/programscompliance overview/programs/[measureId]trend, drivers, risk outlook/programs/hierarchyenterprise→location→provider→patient drill-down/runsrun history and detail/casescase worklist and filters/cases/[id]evidence, actions, timeline; advisory immunization-forecast panel foradult_immunizationcases/campaignsbulk outreach campaign launcher and history/measurescatalog/studio/[id]measure authoring/adminintegration and scheduler controls
POST /api/measures/{id}/ai/draft-cqlPOST /api/measures/{id}/ai/generate-test-fixturesGET /api/programs/{measureId}/risk-outlook?horizonDays=30GET /api/measures/{measureId}/versions/{versionId}/export/mat?format=xmlPOST /api/runs/manualPOST /api/runs/{id}/rerunGET /api/cases?status=openGET /api/exports/runs?format=csvGET /api/auditor/cases/{caseId}/packet?format=json|htmlGET /api/runs/{runId}/measure-report?type=summary|individual|bundleGET /api/runs/{runId}/qrda?format=xmlGET /api/hierarchy/rollup?measureId=&from=&to=POST /api/campaigns(+?dryRun) ·GET /api/campaigns·GET /api/campaigns/:id(CASE_MANAGER/ADMIN)GET /api/immunization/forecast?subjectId=&asOf=(advisory; authenticated; read-time; no schema)GET /api/orders/proposals?measureId=&subjectId=&from=&to=&format=domain|fhir(CASE_MANAGER/ADMIN; advisory; read-time; no schema)
For full API surface and behavioral notes, see docs linked below.
- Architecture
- Data Model
- Measures
- Deploy Guide
- Exports
- Standards Conformance
- Production Readiness — PHI/HIPAA posture, environment split, auth fork, tenancy
- Sprint Index
- Journal
- Changelog
- AI assist is constrained by
docs/AI_GUARDRAILS.md; compliance remains CQL-derived only. - Public API audit actor is always security-context derived.
- Evidence download/upload operations are role-gated and audited.
- Production startup enforces auth, JWT, and CORS safety checks.
- Value-set expansion is pluggable: a
ValueSetResolverport feeds the CQLCodeService(store-backed today, VSAC-ready), with the inline-code path as the config-selectable default (E3.2 / #90).
Licensed under the Apache License 2.0.