Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
981936d
Align Questionnaire catalog with Grove FHIR
PSchmiedmayer Aug 30, 2026
492d60f
Scope Questionnaire round-trip tests to macOS
PSchmiedmayer Aug 30, 2026
bc48cf3
Advance Grove FHIR Dependency
PSchmiedmayer Aug 30, 2026
7a9488f
Pin the Current Grove FHIR Contract
PSchmiedmayer Aug 30, 2026
74672f8
Align the Grove FHIR contract revision
PSchmiedmayer Aug 30, 2026
eef0a4a
Point study definitions at the latest Grove migration
PSchmiedmayer Aug 30, 2026
f8b1006
Follow the latest Grove questionnaire migration
PSchmiedmayer Aug 30, 2026
ae8a95e
Align study definitions with questionnaire scrolling
PSchmiedmayer Aug 30, 2026
57ba936
Follow merged Grove migration
PSchmiedmayer Aug 30, 2026
4d62d87
Advance the Grove FHIR Dependency
PSchmiedmayer Aug 30, 2026
28dadd3
Mark the Heart Risk Measurements for Observation Extraction
PSchmiedmayer Aug 30, 2026
4308040
Advance the Grove FHIR Dependency
PSchmiedmayer Aug 30, 2026
27ff7a5
Advance the Grove FHIR Dependency
PSchmiedmayer Aug 31, 2026
b60af64
Tag the Spanish Instruments With Their Own BCP-47 Locale
PSchmiedmayer Aug 31, 2026
f09af4a
Derive the Questionnaire Catalog From the Study Components
PSchmiedmayer Aug 31, 2026
3d64613
Extract the Blood Pressure Panel Into the Vital Signs Category
PSchmiedmayer Aug 31, 2026
71db001
Hold Marked Items to the SDC Extraction Contract
PSchmiedmayer Aug 31, 2026
ab384d2
Bump the Study Revision
PSchmiedmayer Aug 31, 2026
fc365c6
Document the Questionnaire Conventions
PSchmiedmayer Aug 31, 2026
e159d39
Pin Grove to the Producer-Aligned Revision
PSchmiedmayer Sep 23, 2026
0ea2ffc
Localize the Spanish HeartRisk Units
PSchmiedmayer Sep 23, 2026
3b40191
Link the Measurement Guide Preview and Count Conditions as Interpreta…
PSchmiedmayer Sep 23, 2026
8699f38
Validate the HeartRisk Pair With Grove Before Extraction
PSchmiedmayer Sep 23, 2026
0eb9987
Drop the WHO-5 Markdown That Overrode Its Localized Text
PSchmiedmayer Sep 23, 2026
7472af9
Localize the Spanish Vital Signs Category
PSchmiedmayer Sep 23, 2026
50e0d81
Pin Grove to the Multilingual Questionnaire Revision
PSchmiedmayer Sep 23, 2026
99dac6d
Version the Questionnaires for Their Multilingual Export
PSchmiedmayer Sep 23, 2026
490ffab
Build the Linux Leg Natively Until SwiftPM Honors Platform Conditions
PSchmiedmayer Sep 23, 2026
1d36c45
Merge branch 'lukas/study-variants' of https://github.com/StanfordBDH…
lukaskollmer Sep 28, 2026
6f45125
hmmm
lukaskollmer Sep 28, 2026
05f0a22
Use Grove with standard deployment targets by default
lukaskollmer Sep 28, 2026
d1cbe28
Pin Grove to the review-fix revision
lukaskollmer Sep 28, 2026
49289dd
Pin Grove to the FHIR Export Rework
lukaskollmer Oct 6, 2026
aaa19dc
Pin Grove to the Latest FHIR Export Rework
lukaskollmer Oct 9, 2026
9346b78
Pin Grove to the Latest FHIR Export Rework
lukaskollmer Oct 15, 2026
3a40a9c
Pin Grove to the Latest FHIR Export Rework
lukaskollmer Oct 16, 2026
b48ed6f
Export the HeartRisk Contract Test Through Grove's Public Exporter
lukaskollmer Oct 16, 2026
fa1b3ee
Pin Grove to the Re-Signed FHIR Export Rework
lukaskollmer Oct 16, 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
4 changes: 3 additions & 1 deletion .github/workflows/verify-study-bundle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ jobs:
contents: read
with:
runs_on_labels: '["ubuntu-latest"]'
# Swift 6.4's default build engine ignores transitive platform conditions (Grove#105).
# Swift 6.4.0's default build engine ignores transitive platform conditions,
# which ends up compiling Grove's Apple-only targets on Linux
# (Grove#105 and swiftlang/swift-package-manager#10538)
build_flags: '--build-system native'
16 changes: 13 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ let package = Package(
.executable(name: "MHCStudyDefinitionExporterCLI", targets: ["MHCStudyDefinitionExporterCLI"])
],
dependencies: [
.package(url: "https://github.com/SchmiedmayerLab/Grove.git", exact: "0.3.0-beta.8"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.6.2")
.package(
url: "https://github.com/SchmiedmayerLab/Grove.git",
revision: "6e40cfbffcecafd59b253d6d1d9e2cfbdc89b1d0"
),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.6.2"),
.package(url: "https://github.com/apple/swift-crypto.git", "4.0.0"..<"6.0.0")
],
targets: [
.target(
Expand Down Expand Up @@ -66,7 +70,13 @@ let package = Package(
dependencies: [
"MHCStudyDefinition",
"MHCStudyDefinitionExporter",
.product(name: "GroveStudyDefinition", package: "Grove")
.product(name: "GroveStudyDefinition", package: "Grove"),
.product(name: "GroveFHIRContract", package: "Grove"),
.product(name: "GroveQuestionnaireExtraction", package: "Grove"),
.product(name: "Crypto", package: "swift-crypto", condition: .when(platforms: [.linux])),
// Grove's questionnaire authoring products do not build on the Linux CI leg.
.product(name: "GroveQuestionnaire", package: "Grove", condition: .when(platforms: [.macOS])),
.product(name: "GroveQuestionnaireFHIR", package: "Grove", condition: .when(platforms: [.macOS]))
]
)
]
Expand Down
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!--

This source file is part of the My Heart Counts Study Definitions open-source project
Expand Down Expand Up @@ -26,6 +26,33 @@
Note that the package does not make the actual study definition available as an SPM package; this is intentional.
Instead, the package only implements the code that exports the study bundle, in a format the MHC app can then download from a server and consume.

## Questionnaire Conventions

The instruments are authored under `Sources/MHCStudyDefinitionExporter/Resources/questionnaire/` as `en-US`/`es-US` pairs, each declaring its own `language`.
The pair must stay structurally identical, with the same `url` and `version`: only the display text and the locale metadata differ, and the contract suite compares the two projections to enforce it.
The export merges each pair into one multilingual Questionnaire: the `en-US` source supplies the base strings and `language`, and every `es-US` string becomes a `translation` extension on the string it translates.
The study bundle therefore carries exactly one Questionnaire per instrument, which is what a `QuestionnaireResponse` references and what the app loads and renders in the participant's language.

Any change to instrument content bumps `studyRevision` in `Study.swift` together with the pinned expectation in the tests.
Every change to the exported content also increments that instrument's `Questionnaire.version` in both sources, because `url|version` names one immutable definition.
That covers anything that alters how a response is interpreted — item meaning, datatype, answer choices, required state, a condition, a constraint, the hierarchy, or an extraction marking — and any added, removed or changed translation.

`linkId`s are persisted identifiers.
Submitted `QuestionnaireResponse`s reference them, so a `linkId` is renamed only with a migration, never for tidiness.
Question items use UUIDs; structural anchors that other layers reason about — the HeartRisk wrapper group and its blood-pressure panel — use readable kebab-case names instead.
HeartRisk keeps exactly one top-level group because Grove renders every top-level group as its own section, so flattening the wrapper would split the instrument across three pages.

### Marking Measurements for Extraction

A marked item is extracted into a profiled Observation, following [Grove's measurement extraction guide](https://schmiedmayerlab.github.io/grove-fhir/questionnaire/ci-build/measurements.html).
Marking one takes an `sdc-questionnaire-observationExtract` extension, a single coded `item.code` naming the measurement, and a UCUM `questionnaire-unitOption` for quantities.
A panel is a group carrying the panel LOINC and `valueBoolean: true`; each of its question children carries its own component LOINC and `valueCode: "component"`.
When the target profile fixes a category — the blood-pressure panel's `vital-signs`, for instance — the item must also carry `sdc-questionnaire-observation-extract-category`, or the extracted Observation does not conform.
Measurements whose profile fixes no category, such as blood glucose, deliberately declare none.

An unmarked quantity item is intentionally not extracted; in HeartRisk that covers the second blood-pressure reading, HbA1C, and the cholesterol values, which are collected for the study's own scoring rather than for the measurement exchange.


## Study variants

The exporter produces separate Stanford and Imperial bundles. The CLI defaults to Stanford; select Imperial explicitly:
Expand Down
Loading
Loading