Skip to content

Pilot readiness v1.2.1: fix five release blockers, add IOTA notification pipeline and Epic chart filing - #224

Merged
NeuroKoder3 merged 9 commits into
mainfrom
feat/pilot-readiness-v1.2.1
Aug 1, 2026
Merged

Pilot readiness v1.2.1: fix five release blockers, add IOTA notification pipeline and Epic chart filing#224
NeuroKoder3 merged 9 commits into
mainfrom
feat/pilot-readiness-v1.2.1

Conversation

@NeuroKoder3

Copy link
Copy Markdown
Owner

Summary

Pilot-readiness work for v1.2.1, split into eight reviewable commits. Five
release-blocking defects are fixed, three safety controls added, and the CMS
IOTA notification pipeline is wired end to end with an Epic chart-filing path.

All defects below were pre-existing on main.

Release blockers fixed

  • The production build was broken. index.html had been overwritten by a
    build artifact referencing a hashed bundle that no longer existed, so the app
    could not be packaged at all. Guarded by buildEntryIntegrity.test.mjs.
  • Disaster Recovery was inert in packaged builds. The UI called
    createBackup, verifyBackup and restoreBackup; the Electron client
    exposed only getStatus and listBackups. Now proven by a live
    backup/restore round trip in the e2e critical path.
  • A failed migration was unrecoverable. No restore point existed if a
    migration failed partway. migrationSafety.cjs takes a verified backup first
    and fails closed if it cannot.
  • Eight migrations crashed on partial databases. PRAGMA table_info()
    returns empty for a missing table, so the column guard passed and the
    ALTER TABLE then failed. Fixed systemically, not per-migration.
  • The e2e suite was CI-only. It read an admin password only CI set, so it
    could not run locally — which is how the broken build reached the repo.

Added

  • CMS IOTA § 512.442(d) pipeline — the notice generator existed but nothing
    could reach it. Recording a status transition that blocks organ offers now
    creates a tracked obligation. Delivery distinguishes late from on-time from
    open. An obligation owed to an unnamed dialysis facility is flagged rather
    than shown as discharged.
  • Epic chart filing — builds the FHIR R4 DocumentReference in dry_run,
    manual, or live mode. Outbound transmission requires an explicitly injected
    transport, so no configuration value alone lets this offline-first app reach
    the network. fhirPost deliberately does not retry, because replaying a
    create can file a second copy of a clinical document.
  • System Health page and PHI-safe support bundle — promised by the pilot
    runbook, previously nonexistent. Free text is withheld by default rather than
    scrubbed, since name redaction in prose is unreliable.
  • Auditable vulnerability exceptions — waivers require written
    justification and an expiry; the gate fails on undocumented, expired, stale,
    or newly escalated findings.
  • Renderer bridge coverage guard — scans every api.<ns>.<method>() call
    against the real preload surface, closing the class of defect that made
    Disaster Recovery dead.

Version

Bumped to 1.2.1. The app version was a hardcoded literal in two IPC
handlers and would have drifted from package.json, disagreeing with the
integrity monitor's upgrade check. The release gate also now refuses to pass
against an installer whose version does not match the source.

Test plan

  • 47/47 unit and integration suites pass
  • 39/39 Playwright e2e tests pass, including login → patient → audit →
    backup → restore
  • ESLint clean, TypeScript clean
  • npm audit — 0 unresolved (1 documented exception)
  • Renderer production build succeeds; PHI-screen coverage gate met
  • Requirements TT-R129–TT-R142 traced in the SRS and traceability matrix
  • Rebuild the signed installer at 1.2.1 (needs the code-signing
    certificate; the gate correctly blocks on the stale 1.2.0 binary)

Note for reviewers

Historical compliance records (OQ/PQ protocols, the internal security
assessment) still cite v1.2.0 deliberately — that is the version they were
executed against, and rewriting them would falsify validation evidence.

NeuroKoder3 and others added 8 commits August 1, 2026 16:49
Both specs logged in with TRANSTRACK_INITIAL_ADMIN_PASSWORD but never
passed it to the app they launched. The variable was only ever set at the
CI workflow level, so on a developer machine the app generated a random
setup token instead and every step after login failed.

The suite was therefore effectively CI-only, which is how a broken
production build reached the repository unnoticed. Each spec now owns the
password and passes it into the launched app, so local and CI runs behave
identically. The value only seeds a throwaway database in a temporary
directory.

Co-authored-by: Cursor <cursoragent@cursor.com>
PRAGMA table_info() returns an empty result for a table that does not
exist, so the existing "does this column already exist" guard passed and
the follow-on ALTER TABLE then failed. Eight migrations shared the defect.

Fixed systemically with addColumn()/tableExists() helpers rather than
patching only the migration that happened to surface it, and
ehrMigration.test.cjs is rewritten to be version-agnostic so it exercises
the whole migration chain against a partial database instead of asserting
against a pinned schema version.

Also adds the CMS IOTA evidence tables (migration 17) and the notice body
column (migration 18). Migration 17 stored only a content hash, on the
theory that a deterministic generator makes the body reproducible; that
holds only until a centre edits its template, leaving no way to reprint a
filed notice. The hash stays frozen by trigger and authoritative, so an
altered body remains detectable.

Co-authored-by: Cursor <cursoragent@cursor.com>
A migration failing partway left the database partially upgraded with no
restore point, which is the worst outcome available at a pilot site: the
data is intact but unusable, and recovery depends on whatever backup the
site happened to take.

runMigrationsSafely() copies the database before any pending migration
runs, verifies the copy, and fails closed if it cannot be made. The
restore path is surfaced on failure, and older pre-migration copies are
pruned so the safety net does not grow without bound.

Co-authored-by: Cursor <cursoragent@cursor.com>
The pilot runbook directed administrators to a System Health screen and a
support bundle that did not exist; the only way to read a health snapshot
was to call the IPC method from DevTools.

Free text is withheld from the bundle by default rather than scrubbed.
Redacting names out of prose is not reliable, and a bundle that claims to
be PHI-free while leaking a name in a log message is worse than one that
omits the message. Including full text is a separate explicit choice that
labels the bundle as potentially containing PHI.

phiRedaction.cjs becomes the single source of truth for redaction and
logger.cjs now delegates to it. Its key list deliberately excludes a bare
"name", which was over-redacting non-PHI values such as migration names.

supportBundle.test.cjs feeds deliberately PHI-laden input and asserts no
sensitive literal survives, while also asserting that diagnostic detail is
preserved.

Co-authored-by: Cursor <cursoragent@cursor.com>
The notice generator existed but nothing could reach it. This makes it a
working obligation tracker for CMS IOTA Model 512.442(d).

Recording a waitlist status transition whose impact blocks organ offers
creates the notification obligation in the same operation, so a duty
cannot exist without a tracked deadline. Where the centre's template is
not yet configured the transition is still recorded and the obligation
reported as unmet: the transition is what proves when the statutory clock
started, and discarding it would be worse than a missing notice.

Delivery tracking distinguishes a notice delivered late from one delivered
on time and from one still open, because a surveyor asks different
questions about each. Where a copy is owed to a dialysis facility or
referring provider but none is on file, the obligation is flagged rather
than shown as discharged.

Chart filing (chartFiling.cjs) builds the FHIR R4 DocumentReference in
three modes: dry_run builds and validates but transmits nothing, manual
records a filing done by another route, and fhir_documentreference
performs a real create. Outbound transmission requires an explicitly
injected transport, so no configuration value alone can cause this
offline-first application to reach an external endpoint. A body that no
longer matches its frozen hash is refused.

fhirPost deliberately does not retry, unlike fhirGet: Epic may persist a
resource before a response fails, so replaying a create can file a second
copy of a clinical document. The notification idempotency key travels in
DocumentReference.identifier so a site can reconcile what was filed.

system/DocumentReference.write is excluded from the default scopes.
Requesting write access the application does not use fails customer
security review. The Epic README documents the four steps a site's Epic
team must complete and the HL7 MDM^T02 alternative that avoids write
scopes entirely.

Co-authored-by: Cursor <cursoragent@cursor.com>
The Disaster Recovery screen called createBackup, verifyBackup and
restoreBackup, but the Electron client only exposed getStatus and
listBackups. Those controls were inert in packaged builds: the feature
looked present and did nothing.

Adds the missing methods, registers the System Health and IOTA pages, and
exposes both namespaces through the preload bridge.

rendererBridgeCoverage.test.mjs prevents the whole class of defect by
statically scanning every api.<namespace>.<method>() call in the renderer
and checking it against the real preload surface, loaded by injecting a
fake electron module rather than a hand-written stub that could drift.

buildEntryIntegrity.test.mjs asserts index.html still loads the source
entry module. It had been overwritten by a build artifact referencing a
hashed bundle that no longer existed, which broke the production build
outright.

Co-authored-by: Cursor <cursoragent@cursor.com>
A high-severity React Router advisory was blocking the release gate. The
advisory does not apply to this application, which uses a client-side
HashRouter and no RSC mode, but the only options available were to take a
risky major upgrade or to weaken the gate.

Exceptions are now documented with a written justification, a CycloneDX
VEX analysis state, and a review date. The gate fails on an undocumented
finding, an expired exception, an exception that no longer matches any
real finding, and a severity increase — so a waiver cannot quietly become
permanent.

auditExceptions.test.mjs drives the script with synthetic audit reports to
prove each of those failure modes actually fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
The application version was a hardcoded literal in two IPC handlers, so it
would drift from package.json on any bump and disagree with the integrity
monitor, which reads app.getVersion() to decide whether an upgrade should
re-baseline. Both now resolve from a single helper.

The installer check accepted any version, so the gate passed happily
against a binary built several releases earlier. A green gate sitting next
to a stale artifact is a dangerous signal: the thing a customer installs
would not be the thing that was tested. It now compares the installer
version against package.json and says what to do about a mismatch.

Registers the new suites, adds requirements TT-R129 through TT-R142 with
traceability, and records the release in the changelog.

Co-authored-by: Cursor <cursoragent@cursor.com>
@strix-security

strix-security Bot commented Aug 1, 2026

Copy link
Copy Markdown

Strix is installed on this repository, but we couldn't run this PR security review because this workspace's trial has ended. Add a card to resume code reviews here.

Comment thread electron/services/supportBundle.cjs Fixed
Comment thread electron/services/supportBundle.cjs Fixed
Two CI failures on #224, both in the support bundle work.

The build failed because supportBundle.test.cjs requires logger.cjs, which
destructures `app` and `crashReporter` from `electron` at load time. CI installs
with the Electron binary download skipped, so that require throws there while
succeeding locally. The suite now injects an `electron` stub into the require
cache the way healthCheck.test.cjs already does, keeping it a pure Node test.

CodeQL flagged readLogTail for a check-then-use race and for opening a
predictably-named temp path. The race is real rather than theoretical:
logger.cjs rotates the files readLogTail reads, so the log can be renamed
between existsSync and openSync. It now opens once and measures the descriptor
with fstat, so size and bytes always come from the same file, and returns empty
if the file went away instead of throwing. The temp path came from the tests
themselves, which now work inside a per-run mkdtemp sandbox.

Co-authored-by: Cursor <cursoragent@cursor.com>
@NeuroKoder3
NeuroKoder3 merged commit 0a6d80e into main Aug 1, 2026
16 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