Hospital MAR Source and Integration
Canonical medication sources, live MAR commands, writer protection, and verification limits.
Delivery Boundary
Programme U6 connects nursing MAR to canonical Clinical medication records. Its focused plan has eight local units. Local U1 adds characterization tests and freezes the API contract. Local U2 adds source identity and history constraints. The U2 execution record lists proof and remaining gates. Prescriber commands and alternate-writer guards have a local checkpoint; the U3 execution record lists evidence and limits. Local U4 nursing commands and U5 authorized facility APIs have focused regression coverage; see the U4 execution record. The current source passes full backend CI, changed-source lint, and the scoped external review follow-up. The checkpoint is local on the integration branch. Local U6 adds the typed adapter and private recovery store. Local U7 adds the live worklist, source controls and nursing UI. Local U8 has passing real-HTTP and authenticated browser journeys in both presets; see its execution record and QA guide. Whole-PR review, deployed QA and human acceptance remain separate gates. Programme U7 Recovery is implemented locally on the same PR. Programme U8 signed discharge remains separate work.
The live /hsp/mar route uses canonical MAR APIs and reports missing policy or source availability.
The mock page is not clinical acceptance. Do not connect it directly to generic
medication CRUD. No migration, permission-default change, or clinical activation
is part of local U1.
Source Ownership
| Source | Owner and meaning |
|---|---|
Clinical::MedicationRequest | Clinical order identity, medication, instructions, status, and prescriber |
Clinical::MedicationAdministration | Clinical outcome and event time; not a stock movement |
| Versions, occurrences, commands | Clinical source identity and immutable history; prescriber and nursing command services own changes |
| Case-medication link | Hospital case context with scoped source links; the live workqueue projects canonical care |
| Effective grants and assignments | Identity; shell owns RBAC management |
| Feature flags | Admin; Hospital does not add a flag editor |
Use current Hospital readiness commands for locking, operation receipts, and transactional audit patterns. Use the Lab adapter for typed transport, scope-aware query keys, and explicit unavailable states. Follow the software pattern review. Local U2 uses scoped database constraints and immutable history guards. It does not add a second medication source or a new clinical authority.
User-Bound Retry Recovery
MAR query, case-context and retry keys include the authenticated User ID as well as tenant, facility and profile. Logout unmounts the workbench and aborts its requests. A same-role user switch cannot inherit a pending clinical intent. Both direct command results and receipt lookups must match the original actor. An uncertain result keeps its original key until confirmation and fresh reads.
Old entries without a User ID remain untouched and block new commands in that scope for supervised recovery. Never assign an unowned intent to the next user or delete it to bypass recovery. The store retains selectors and a digest, not clinical field values.
Summary reads require their own disclosure audit, even on an empty or out-of-range page. Audit failure returns unavailable. Setup-gap history checks use one capped batch. Canonical dosage objects and arrays keep their shape; neither form supplies an approved schedule without explicit source enrollment.
Corrections from an existing non-dose outcome to another non-dose outcome can retain a time after source stop or revision. Physical-dose corrections still require historical authority. Required command audit must be persisted in the transaction; nil, unsaved or raised audit failures reject the whole command.
Managed Source Constraints
Local U2 adds MedicationMarVersion, MedicationDoseOccurrence,
MedicationDoseCommand, and Hospital::CaseMedicationLink. Existing requests
gain a nullable current-version pointer. Administrations gain nullable MAR links
and User performer/recorder fields. Existing unlinked rows need no backfill.
Composite foreign keys and null-safe checks bind tenant, facility, patient, registration, request, version, encounter, occurrence, and outcome. Immutable versions and receipts control source changes and occurrence projections. Managed source identity cannot be changed or deleted through generic SQL. A managed request cannot receive an untracked generic administration. A correction retains the original event and performer. New care must name the command actor as performer. Stop and revision receipts cannot clear a retained current outcome without its correction receipt. An unresolved occurrence can still be cancelled.
These are source constraints, not actor authorization. Local U3/U4 must check the
current source under lock, approved policy, current assignment, effective grants,
and audit. MedicationDoseCommand.expected_revision checks the selected instruction
version. It is not the wire expected_source_revision precondition. Services must
store accepted current, historical, and resulting version preconditions explicitly
in the immutable receipt and fingerprint the complete normalized command.
Current Source Behavior
The characterization suite is
backend/domains/clinical/test/services/medication_mar/source_characterization_test.rb.
Its T01-T04 labels map to local U1 in the focused plan.
These tests describe existing source behavior, including gaps. They do not prove
future MAR authorization, non-bypass RLS, or managed-source protection.
Fields And Readers
medication_requests has JSON medication, dosage_instruction, dispense_request,
and reason_code, with note, optional patient_facility_id, optional encounter_id,
and optional Practitioner requester_id. There are no SQL-backed request fields
named category, medication_display, quantity_value, refills_allowed, or notes.
The old prescription create service names unsupported fields. Do not reuse that
builder unchanged.
Request helpers accept a dosage hash or array and read text/frequency from it.
This does not turn a text instruction into an approved MAR schedule.
MedicationRequestBlueprint normal view supplies identity/display; detailed view
adds raw medication/instructions/dispense data. The normal view alone is not a
structured source-authoring contract.
Administration helpers read nested dosage.dose.value, dosage.dose.unit, and
dosage.route.display or text. The generic controller permits a different flat
dosage shape. Flat dose_value/dose_unit values persist but do not populate those
nested helpers. Preserve exact decimal strings and coded units in the new writer.
The administration model's medication_display method reads name or
code.display, not medication text or the SQL column of the same name.
The characterization test records this mismatch; local U1 does not change it.
Later source/UI integration must use an explicit common display contract and
verify canonical readers rather than hide the mismatch in seed data.
State And Encounter Replacement
Request transitions preserve the row identity. An active request can go on hold.
The current state machine does not permit on_hold directly to stopped; it must
return to active first. Later MAR source commands must implement the agreed
version/state contract without bypassing it through generic status writes.
Administration completion requires an explicit effective time at model level.
entered_in_error preserves the same record and original event time. Legacy
administration paths do not establish a managed correction chain or stable dose
occurrence. Local U2 adds those constraints for explicitly managed records.
Encounters::SaveClinicalDataService replaces medications in the encounter's
collection when a non-empty medication array is supplied. An incoming row ID is
not used to preserve source identity.
Important runtime detail: the service calls association delete_all, but
Encounter#medication_requests has dependent: :nullify. Rails therefore clears
the old rows' encounter_id instead of deleting the rows. Old orders stay active
and new order UUIDs are created. An existing administration still references its
old order and original encounter. A guard must prevent this detachment before
MAR enrollment can ship. A check that only intercepts SQL DELETE is insufficient.
Absent and empty medication arrays currently leave the collection untouched. A mixed observation/medication save uses one transaction. Invalid medication replacement rolls back the observation change and both old order links. Managed-order whole-batch rejection and concurrent enrollment tests belong in local U3, after local U2 creates the managed source objects.
Actors And Scope
A nurse can have a real Identity::User, Identity::Staff, and current facility
Identity::StaffRole without a Practitioner. Legacy administrations use optional
Practitioner performer_id. U2 does not infer User provenance for those rows.
Do not create a Practitioner just to fill that field. Local U2 adds User links for managed outcomes;
later source services must derive them from authenticated identity.
Existing Practitioner exports use Practitioner/:id. An administration without
a Practitioner has no performer reference in the current FHIR blueprint.
Do not invent a FHIR User resource when adding internal User provenance.
Keep unmapped Staff export explicitly unavailable until an approved mapping exists.
Staff membership does not receive dose-administration/manage grants by default.
Current assignment and an explicit effective grant are both required in the new
policy. Do not use StaffRole.permissions as a second permission resolver.
A surgical case and matching canonical order can both exist without an encounter. The case validates its facility registration and encounter's patient. In contrast, the current medication-request model accepts a registration for another patient or facility. Generic source persistence is not an eligible-order selector. Local U1 captures that legacy gap. Local U2 proves managed source-link agreement. Local U5 proves authorized eligible-order selection through policy and HTTP request tests. Local U6 adds typed frontend transport and local U7 connects the live UI. Deployment and D4 clinical authorization acceptance remain open.
Writers That Need Protection
Before enrollment is available, inspect these current domain paths and protect all routes that can change managed identity, source data, or outcome history.
Path under backend/domains/clinical/ | Current entry point and required later check |
|---|---|
controllers/medication_requests_controller.rb | Create/update/destroy/transition/dispense; reject managed-source bypass and caller reparenting |
controllers/medication_administrations_controller.rb | Create/update/destroy/complete; reject generic administration against an enrolled request even without an occurrence selector |
services/encounters/save_clinical_data_service.rb | Whole-collection replacement/detachment; reject the entire mixed batch before changing managed rows |
services/prescriptions/create_service.rb | Old builder uses unsupported fields; new MAR authoring needs a bounded current-schema writer |
services/prescriptions/dispense_service.rb | Assumes unsupported request helpers/fields; not an administration or Inventory integration path |
services/ai/suggestion_acceptance_service.rb | Creates canonical orders through its resource table; new orders remain unmanaged until explicit prescriber enrollment |
services/patients/import_longitudinal_record.rb | Copies most source columns via as_json.except; explicitly strip future MAR pointer/lineage fields so an imported snapshot cannot inherit source authority |
models/medication_request.rb | administrations nullifies its request link on destroy; managed history must not detach |
models/encounter.rb | Medication associations nullify on parent deletion; reject managed detachment |
models/patient.rb | Medication associations destroy on parent deletion; preserve managed source and clinical evidence |
The current Encounters::PlaceDraftOrdersService places ServiceRequests only.
It does not activate medication requests. Do not infer medication authority from
an encounter finish event. Inspect any new writer added before local U3 completes.
Local U2 guards direct SQL and bulk source mutation. Local U3 must still add
controlled writer errors, whole-batch rejection, and concurrent enrollment proof.
Callbacks alone do not satisfy the source-protection contract.
Canonical read paths to verify during later integration include the medication
blueprints, encounter detail, Patients::LongitudinalRecordService,
Patients::LhrViews::MedicationsTransformer, prescription data/PDF builders,
Clinical FHIR exports, and Integration ABDM builders. Reader compatibility is
separate from exposing Hospital action controls.
Wire And Clinical Contract
The MAR API section is the contract index. The focused plan supplies the full instruction, lock, state, and correction rules.
- A medication-request ID identifies the order. A version identifies its approved instructions. An occurrence ID identifies one scheduled or recorded PRN event. An administration ID identifies the canonical outcome. A UUID operation key identifies one intended command across retries.
scheduled_occurrenceandprn_occurrencehave occurrence IDs.prn_availabilityandsetup_gapdo not. Never invent a recurring PRN due time.- Every write uses a strict
commandenvelope, expected versions, server-derived actor/context, exact dose/unit confirmation, and required reasons. - Same-key replay returns one receipt. Authorized absence is HTTP 200 with
data.receipt=null. A denied, aborted, or unavailable lookup is not absence. - RLS and current facility/resource policy are both required. All clinical writes need an approved selected D4 policy and eligible current clinical assignment.
- Nursing records care separately from stock, pharmacy review, billing, and discharge. Correction is not permission to give another dose. An empty worklist is not clinical clearance.
For example, an occurrence URL uses the occurrence selector:
POST /clinical/facilities/:facility_id/mar_orders/:occurrence_id/administrationsIts command.action=administer input confirms the prescribed dose and route with
the expected source revision and occurrence version. The patient, medication
request, and actual performer come from authorized source and identity records,
not browser-supplied names. Local U5 implements the backend route and local U7
connects its frontend. Deployment and D4 acceptance remain open.
Verification And Manual QA
Run focused tests only against an owned disposable test database. From backend/:
RAILS_ENV=test PARALLEL_WORKERS=1 bin/rails test \
domains/clinical/test/services/medication_mar/source_characterization_test.rb \
domains/clinical/test/models/medication_request_test.rb \
domains/clinical/test/models/medication_administration_test.rb \
domains/clinical/test/services/encounters/save_clinical_data_service_test.rb \
domains/clinical/test/requests/encounters_save_clinical_data_test.rb \
domains/clinical/test/requests/medication_requests_test.rb \
domains/clinical/test/requests/medication_administrations_test.rbSet DATABASE_URL to that disposable database before running this command.
Local U1 uses characterization, not a failing-feature/fix pair. It changes no
production behavior. A test that documents a gap must not be reported as proof
that the gap is closed. Replace or extend those assertions when its owning later
unit implements the protection. Use the
execution record for model routing, test and review evidence,
and open approvals. The execution record, not plan checkboxes, tracks delivery.
- Backend and frontend owners review source and wire examples; confirm that request, version, occurrence, administration, and operation-key IDs differ.
- Review the two-order replacement test and confirm the old encounter links clear while existing administration provenance remains; accept the local U3 guard requirement.
- Review a Staff nurse with no Practitioner; identify the shell grant and assignment checks required before any future nursing write.
- Review a day-care case with no encounter; confirm no Recovery dependency is introduced and U5 authorized source selection remains facility scoped.
- Name qualified clinical/nursing reviewers and record open D4 policy values and acceptance. Do not fill them with synthetic fixtures or inferred approval.
Deployment, human nursing QA, D4 approval, and combined pilot acceptance remain separate gates. Do not enable live dose actions on the strength of local U1 tests.