Skip to content

feat(check-in-wallet): SMART Health Check-in web wallet for Kill the Clipboard #2 - #5

Merged
cursor[bot] merged 3 commits into
mainfrom
cursor/check-in-wallet-2518
Oct 17, 2026
Merged

cursor[bot] merged 3 commits into
mainfrom
cursor/check-in-wallet-2518

Conversation

@pswider

@pswider pswider commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Adds a static SMART Health Check-in 1.0 web wallet under apps/check-in-wallet/ so RealActivity can test at CMS Kill the Clipboard Connectathon #2 (Tue 3 Nov 2026, 2-5 PM ET). Target public https URL by 27 Oct. This PR does not deploy anything or register the wallet.

What shipped

  • Web wallet opened by a Verifier via window.open, using @smart-health-checkin/client v0.4.4 (Apache-2.0) for postMessage, request parse, selectEntries, checkWalletResponse, mdoc wrap, and HPKE.
  • Consent copy: "A website is asking for your health information" plus the browser-stamped origin. Item-by-item share or decline. A second click is ignored while a reply is in flight.
  • FHIR R4 4.0.1 / application/fhir+json with US Core profiles: Patient, Condition (problems), AllergyIntolerance, MedicationRequest, Immunization. The referenced prescriber (Dr. Dave Matthews) is included when problems or medications are shared.
  • Insurance card always unavailable (or declined if the patient turns it off). Tula policy: health data only. No Coverage resource.
  • Inline PHQ-2 rendered; QuestionnaireResponse echoes the requested canonical exactly. Sharing is blocked until every question is answered.
  • Synthetic patient only: Dylan Meyer / Dr. Dave Matthews.
  • Local verifier at demo.html for same-origin dry runs.
  • Vitest suite (20 tests) including official checkWalletResponse.
  • Production build injects a Content-Security-Policy meta tag (script-src 'self', no inline scripts).
  • CI workflow on wallet path changes. README covers run + GitHub Pages deploy. participant.example.json matches the connectathon registration schema.

Review fixes

A review pass closed these gaps without changing the three minimum scenarios:

  • An item that does not accept application/fhir+json is unsupported for that item, so the library does not reject the whole sealed response.
  • Remote questionnaires are fetched once, over https only (http limited to localhost / 127.0.0.1), with cookies omitted and redirects rejected. The loaded questionnaire is reused on submit.
  • Incomplete forms return status error ("The form was not completed.") and the consent screen shows "Answer every question before sharing."
  • Insurance detection matches coverage canonicals (/C4DIC-Coverage, /us-core-coverage, /insurance-card/) on profiles and profilesFrom.
  • Chart entries are cloned per response. Absolute fullUrls let selectEntries pull in the prescriber.
  • Response JSON over 512 KB throws before seal. The synthetic chart is far under that cap.
  • demo.html renders a failed result if wallet.start rejects.

Scenarios vs the SMART Testing EHR

The live Testing EHR was not run from this PR (no public https URL, and this change does not deploy). After the review fixes, the same client library the Testing EHR uses accepted all three minimum scenarios on a local verifier (wallet.start + decrypt + spec checks), rechecked in the browser against the production build:

Scenario Request Local verifier + spec checks Live Testing EHR
1. Share records records.json Pass. patient/problems/allergies/medications/immunizations fulfilled; coverage unavailable. Origin shown. Prescriber listed. Not run. Needs a public https wallet URL.
2. Fill in a form form-phq2.json Pass. Incomplete share is blocked. After both answers, phq2 is fulfilled with canonical https://smart-health-checkin.org/connectathon/Questionnaire/phq-2.json. Not run.
3. Decline one item records.json Pass. Immunizations declined; other health items fulfilled; coverage unavailable. Not run.

Unit tests also pass checkWalletResponse (empty issue list) for those three plus unknown-selector (unsupported), a non-FHIR accept list, and the 512 KB JSON cap.

After a human deploys https, add the URL as a custom wallet on https://smart-health-checkin.org/connectathon/testing-ehr/ and file official results.

What is still missing

  • Public https hosting and connectathon registration (status is not-yet).
  • Official Testing EHR result filings.
  • SMART Health Cards (insurance and immunization card scenarios).
  • First-class coverage of advanced scenarios (GAD-7 by reference, versioned canonical, large-response, no-selector, shared artifact). Form-by-URL fetch exists; unknown kinds return unsupported.
  • Native Android / iOS wallets.
  • Live Tula workspace FHIR. The wallet ships a bundled synthetic chart, not ~/.openclaw/workspace/tula/fhir/.
  • Automatic GitHub Pages publish workflow (documented, not enabled).

Could not verify

  • Live SMART Testing EHR. Local pass uses the same client library; the public EHR page was not exercised.
  • Whether the 512 KB limit is measured on the SMART JSON or on the sealed mdoc. This code checks the JSON. The synthetic chart is small either way.
  • Official US Core must-support validation. Resources claim the profiles and carry the usual required fields; no official validator was run.
  • frame-ancestors 'none' cannot be set from a meta tag. The host must send that as an HTTP response header. README says so.
  • Form-by-reference still GETs an attacker-chosen https URL when the consent screen opens, before the patient shares. Cookies and redirects are blocked. Inline PHQ-2 does not fetch.
  • Questionnaire item types other than choice and short text (boolean, date, integer, quantity) render as a text field stored as valueString. The minimum scenarios only need PHQ-2 choice.
  • HPKE / mdoc sealing inside the pinned client library was not re-audited.

Proposed wallet URL and how to deploy

Proposed: https://realactivity.github.io/tula/check-in-wallet/

Static dist/ from cd apps/check-in-wallet && npm ci && npm test && npm run build. vite.config.ts uses base: "./" so a Pages subpath works. No server, no secrets, no PHI store. The production build injects a CSP meta tag. The host should also send Content-Security-Policy: frame-ancestors 'none'.

Human steps (do not do them from this PR):

  1. Merge when ready.
  2. Enable GitHub Pages (Actions or gh-pages) and publish apps/check-in-wallet/dist.
  3. Confirm https landing page and demo.html.
  4. Submit the connectathon registration form from apps/check-in-wallet/participant.example.json. Set status to up only when anyone can open the URL.
  5. Self-test the three minimum scenarios on the SMART Testing EHR and file results.

Alternative: Azure Static Web Apps or https://checkin.realactivity.ai/ if Pages is not acceptable. That needs DNS and an owner.

Human decisions

  • Confirm the public URL (Pages vs custom domain).
  • Confirm connectathon contact (name + GitHub, Slack, or email). Listed GitHub usernames auto-merge on the connectathon repo.
  • Confirm component id tula-web-wallet is unique.
  • Flip status from not-yet to up only after the URL is public.
  • Confirm "Tula Check-in Wallet" naming against TRADEMARK.md.
  • Confirm it is acceptable to host a synthetic-only wallet on the public realactivity/tula Pages site.
  • Whether to wire the wallet to a live local FHIR directory after the connectathon (out of scope here).

How to run

cd apps/check-in-wallet
npm install
npm test
npm run dev
# wallet: http://localhost:5173/
# local verifier: http://localhost:5173/demo.html
Open in Web Open in Cursor 

cursoragent and others added 3 commits October 13, 2026 05:11
Give RealActivity a connectathon-ready web wallet for Kill the Clipboard
#2: origin-shown consent, item-by-item share or decline, US Core FHIR R4
for the synthetic Dylan Meyer chart, PHQ-2 inline form, and insurance
always unavailable under Tula's health-data-only policy.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Paul J. Swider <pswider@realactivity.com>
Remote forms were fetched twice and from any URL, a non-FHIR accept
list could fail the whole sealed response, and the consent screen
could submit twice or hide a referenced prescriber.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Paul J. Swider <pswider@realactivity.com>
The connectathon needs a public https wallet URL. This workflow builds
the static wallet and deploys it to /tula/check-in-wallet/ once a repo
admin enables Pages with the GitHub Actions source.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Paul J. Swider <pswider@realactivity.com>
@pswider
pswider marked this pull request as ready for review October 17, 2026 16:20
@cursor
cursor Bot merged commit 31e0b69 into main Oct 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants