Medication Order
Table of contents
- Medication Order
- Intent
- Summary
- Structure
- Examples
- Happy path — inpatient order through completion
- Amendment — dose correction before dispensing
- Hold and reinstate — surgical pause
- Rejection path — amendment attempted after dispensing
- Rejection path — cancel attempted after dispensing
- Rejection path — dispense without verification
- Rejection path — action against an on-hold order
- Regulated adversarial scenarios
- Generation acceptance
- Edge cases and explicit non-goals
- Composition notes
- Standards references
- Status
- Lineage notes
A healthcare primitive: an immutable prescription record binding a prescriber, a patient, a medication, and a dosing regimen — from initial order through verification, dispensing, administration, and terminal resolution. Amendments before dispensing create successor orders; orders stopped after dispensing become Discontinued; orders terminated before dispensing are Cancelled.
Intent
A prescriber — physician, nurse practitioner, physician assistant, or authorized clinical system — places a medication order specifying what drug to give, to whom, in what dose and form, by what route, on what schedule, and for how long. That prescription drives a regulated chain of custody: a pharmacist verifies it before any dispensing occurs; a dispenser prepares and releases the medication; a nurse or patient administers it; the course completes or is terminated. At every step, the actor who performs the action is permanently attributed.
The pattern addresses three simultaneous clinical requirements. First, the prescription record must be faithful to what was ordered — the medication identity, dose, route, and frequency are fixed at order time; errors are corrected by explicit amendment (before dispensing) or explicit cancellation and reorder (after dispensing), never by silent edit. Second, every role in the chain — prescriber, verifier, dispenser, administerer — must be permanently attributed to the actions they take, and that attribution must survive adversarial scrutiny: DEA controlled-substance audit, wrong-medication dispute, diversion investigation. Third, the amendment boundary at dispensing is clinically load-bearing: a dose change before the pharmacy has acted is a simple correction; a change after medication has left the pharmacy requires discontinuing the active order and placing a new one.
This is a freestanding (can be specified without naming any other pattern) concept in the EOS (Essence of Software — Daniel Jackson’s framework for specifying software concepts as freestanding, composable units) sense. It carries its own state (the medication order record set), its own actions (order, amend, verify, hold, reinstate, dispense, administer, complete, cancel, discontinue, read), and its own invariants (core-field immutability, pre-dispensing amendment only, hold-and-reinstate mechanics, terminal-state finality, role attribution). Composing patterns add access control, cryptographic non-repudiation, retention policy, tamper-evidence, and controlled-substance DEA reporting. The atom imposes no semantics on what the medication is clinically; it imposes the structural guarantee that the order is faithful to what was prescribed, by whom, and how that prescription was fulfilled.
The atom models the full prescription lifecycle — including dispensing and administration — as a unified record rather than decomposing those stages into separate entities, as HL7 FHIR (Health Level 7 Fast Healthcare Interoperability Resources — a standard for exchanging healthcare information) does with MedicationRequest, MedicationDispense, and MedicationAdministration. The FHIR decomposition serves interoperability across independently-operated systems that may own separate pieces of the prescription lifecycle; this atom prioritizes a single auditable chain of custody within a deployment. Dispensing and administration here are state transitions on the order record, not independent freestanding entities — they carry no state machines of their own, and their records are meaningful only relative to the order they act on. The composing concern to separate them does not arise until a second domain in the library requires generic material-issuance semantics (blood products, implants, durable medical equipment) independent of a prescription record; absent that evidence, separating them adds coordination overhead without proportional benefit and fragments the attribution chain this atom is built to preserve.
Summary
Medication Order is the atom that records the complete lifecycle of a prescription from initial placement through terminal resolution. A prescriber places an order specifying the drug, patient, dose, route, frequency, and duration. That order then passes through a regulated chain of custody — pharmacist verification before any dispensing occurs, dispenser release of the medication, nurse or patient administration, and eventual completion or termination — with every actor at every stage permanently attributed. The atom’s core guarantee is that this chain of custody is both immutable (unchangeable once written) and complete: no step can be silently skipped, no actor can be silently omitted, and no record can be retroactively altered.
Three requirements are addressed simultaneously. First, the core prescription fields — medication identity, dose, route, frequency — are fixed at order time; corrections before dispensing create a successor order via amendment, requiring fresh pharmacist verification; corrections after dispensing require discontinuing the active order and placing a new one, because the physical medication has already left the pharmacy’s custody. Second, every role in the chain — prescriber, verifier, dispenser, administerer — is permanently attributed and cannot be edited after the transition completes. Third, the boundary between cancellation (medication never dispensed) and discontinuation (medication dispensed but stopped) is clinically and regulatorily load-bearing, particularly for DEA controlled-substance accounting, and is enforced structurally.
The atom models the full prescription lifecycle as a single record rather than splitting dispensing and administration into separate entities (as HL7 FHIR does). This is a deliberate design choice that prioritizes a tight, single-chain attribution model over broader interoperability. The nine states are: Ordered, Verified, Dispensed, Administered, Completed, Cancelled, Discontinued, Amended, and On Hold. The terminal states (Completed, Cancelled, Discontinued) are absorbing (no further transitions are possible). Amended orders are inactive; clinical workflow continues on the successor. On Hold orders accept only the reinstate action, which returns the order to its prior state.
Amendment is pre-dispensing only: an order that has reached Dispensed, Administered, or Completed state cannot be amended; the physical medication has left the pharmacy. The hold/reinstate pair provides a reversible suspension mechanism for any active state — surgical pause, drug interaction review, formulary substitution — while recording who held it, why, and when, and returning to the exact lifecycle position on reinstatement.
The most common uses are: inpatient electronic health record systems managing medication administration records, outpatient pharmacy systems processing prescriptions, DEA controlled-substance tracking (21 CFR Part 1306 and EPCS Part 1311), HIPAA (US Health Insurance Portability and Accountability Act) audit compliance, and Joint Commission medication management standards. The atom is grounded (passed all required review passes and is stable enough to generate from).
Structure
Store instance model
The Medication Order atom operates against a named store instance. A store_name identifies the instance; multiple instances coexist in real systems — one per health system, facility, department, or care team, depending on deployment topology. The atom specifies what one instance is and how it behaves; composing patterns and deployment configuration determine how many instances to instantiate. order_id values are unique within a store instance; uniqueness across instances is a composing concern. patient_ref is an opaque reference scoped globally — the same patient_ref may appear in multiple store instances for the same patient across care settings. Calls implicitly target a single routed instance; the mechanism by which a caller’s call reaches a specific instance (service binding, URL endpoint, namespace prefix) is a deployment-routing concern, not defined by this atom.
Identity model
Each order has an opaque, immutable, system-generated order_id — assigned on order, never reused, never reassigned within the store instance. The id is the order’s identity; the medication, dosing details, and lifecycle events are properties of the order, not its identity.
patient_ref is an opaque reference to the patient. Set on order, immutable. It is not the order’s identity — two orders for the same patient have different order_ids. patient_ref is inherited unchanged by any successor order created by amend.
prescriber_ref is an opaque reference to the prescriber who placed the order. Set on order, immutable. prescriber_ref is inherited unchanged by any successor order created by amend — prescribing authorship belongs to the original prescriber. Amendments (corrections added to a record without replacing it — the original remains) carry their own amended_by to record who made the correction; the original prescriber_ref is never changed on any order in the amendment chain.
medication_ref is an opaque reference identifying the specific drug and formulation (for example, a formulary item code or National Drug Code). Set on order, immutable. medication_ref is inherited unchanged by any successor order created by amend. An order placed for the wrong medication must be cancelled and re-ordered; amendment cannot change the medication identity. This is a structural property of the atom — amend does not accept medication_ref as a parameter, making a medication change via amendment architecturally impossible rather than runtime-rejected.
Inputs
ordercalls from prescribers, each carrying a patient reference, prescriber reference, medication reference, prescribed dose, dose unit, route, frequency, optional duration, optional clinical evidence reference, and optional explicit timestamp.amendcalls that correct dosing parameters on a pre-dispensing order, carrying the order id, the amending clinician, updated dosing parameters, and a required reason.verifycalls from pharmacists who have reviewed and cleared the order for dispensing.holdcalls that temporarily suspend the order, carrying the actor and a required reason.reinstatecalls that resume a held order, returning it to its pre-hold state.dispensecalls recording the pharmacy releasing the medication, carrying the dispenser reference, quantity, optional lot number, and optional timestamp.administercalls recording the medication given to the patient.completecalls closing the order after the full course is administered.cancelcalls terminating the order before any dispensing has occurred.discontinuecalls terminating the order after dispensing has begun.readqueries from clinical systems, pharmacy systems, analytics pipelines, and audit processes.
Actions
-
order(patient_ref, prescriber_ref, medication_ref, dose, dose_unit, route, frequency, duration?, clinical_evidence_ref?, ordered_at?) → order_id | rejected(invalid-order | storage-failure)— create a new Ordered medication order.ordered_atdefaults to the receiving node’s wall clock if not supplied; when supplied, it must not be in the future.durationis optional — its absence models an open-ended order with no predetermined termination date; open-ended orders remain active until explicitly completed or discontinued.clinical_evidence_refis an optional opaque reference to clinical evidence (such as a Clinical Observationobservation_id) that informed the prescribing decision; it is advisory metadata on the order, not a structural dependency — the atom does not interpret it. If supplied, it must contain at least one non-whitespace character; a supplied empty or whitespace-only value isinvalid-order. When absent, the field is not present on the order record; there is no nil-vs-absent distinction for this field. -
amend(order_id, amended_by, dose?, dose_unit?, route?, frequency?, duration?, reason) → new_order_id | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-dispensed | invalid-request | storage-failure)— create a successor order correcting one or more dosing parameters of the named order. Valid only for orders in Ordered or Verified state. The original transitions to Amended and acquires asuccessor_id; the successor is Ordered with apredecessor_idreferencing the original.medication_ref,patient_ref, andprescriber_refare inherited by construction —amenddoes not accept these as parameters. The successor starts in Ordered state regardless of whether the original was Ordered or Verified, because the amendment changes the clinical content and requires fresh pharmacist review before the revised order may be dispensed. At least one of the dosing parameters (dose,dose_unit,route,frequency,duration) must differ from the original’s current values; anamendcall whose supplied parameters all match the original isinvalid-request— an amendment that changes nothing is not an amendment. Settingdurationto nil in anamendcall is valid and converts a duration-bounded order to an open-ended one.amended_byandreasonmust each contain at least one non-whitespace character; either being empty or whitespace-only isinvalid-request.already-dispensedcovers Dispensed, Administered, and Completed states — all post-dispensing. Anamendoperation requires two durable writes; seeamendtwo-write atomicity in Edge cases. -
verify(order_id, verifier_ref) → verified | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-completed | not-in-ordered-state | invalid-request | storage-failure)— record pharmacist review and clearance. Valid only for orders in Ordered state.verifier_refmust contain at least one non-whitespace character (invalid-request). Recordsverifier_refandverified_aton the order; both are immutable thereafter.already-completedcovers Completed state — a terminal order.not-in-ordered-statecovers Verified, Dispensed, and Administered states — the order has already been verified or has progressed beyond the verification stage. -
hold(order_id, held_by, reason) → held | rejected(not-known | already-on-hold | already-completed | already-cancelled | already-discontinued | already-amended | invalid-request | storage-failure)— temporarily suspend the order from any actionable state (Ordered, Verified, Dispensed, or Administered). Records the current state asprior_state, recordsheld_by,hold_reason, andheld_at; all are set at hold time.held_byandreasonmust each contain at least one non-whitespace character (invalid-request). Hold fields are set once per hold transition (Invariant 12); a subsequentholdafter reinstatement overwrites these fields with the new hold’s values — see Invariant 12 and Multiple hold cycles in Edge cases. -
reinstate(order_id, reinstated_by) → reinstated | rejected(not-known | not-on-hold | invalid-request | storage-failure)— resume a held order, returning it to the state stored inprior_state. Recordsreinstated_byandreinstated_at.reinstated_bymust contain at least one non-whitespace character (invalid-request).not-on-holdcovers all non-On Hold states; terminal and Amended states cannot be on hold in the first place, so their specific rejections are not needed here. -
dispense(order_id, dispenser_ref, quantity, lot_number?, dispensed_at?) → dispensed | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-completed | not-verified | already-dispensed | invalid-request | storage-failure)— record the pharmacy releasing the medication. Valid only for orders in Verified state. Recordsdispenser_ref,quantity(a positive number),lot_number(if supplied), anddispensed_at(wall clock if not supplied); all are immutable after the dispense transition.dispenser_refmust be non-empty and non-whitespace-only;quantitymust be strictly positive; either violation isinvalid-request.not-verifiedcovers Ordered state — an order awaiting pharmacist review may not be dispensed. -
administer(order_id, administerer_ref, administered_at?) → administered | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-completed | not-dispensed | already-administered | invalid-request | storage-failure)— record the medication given to the patient. Valid only for orders in Dispensed state. Recordsadministerer_refandadministered_at(wall clock if not supplied); both are immutable after the administration transition.administerer_refmust be non-empty and non-whitespace-only (invalid-request).already-administeredcovers orders already in Administered state — the order stays Administered until explicitly completed or discontinued; subsequent dose events for multi-dose regimens are a composing concern (see Multi-dose regimens in Edge cases). -
complete(order_id, completed_by, completed_at?) → completed | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-completed | not-administered | invalid-request | storage-failure)— close the order after the full course has been administered. Valid only for orders in Administered state. Recordscompleted_byandcompleted_at(wall clock if not supplied); both are immutable after the completion transition.completed_bymust be non-empty and non-whitespace-only (invalid-request). -
cancel(order_id, cancelled_by, reason) → cancelled | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-completed | already-dispensed | invalid-request | storage-failure)— terminate the order before any dispensing. Valid only for orders in Ordered or Verified state. To cancel a held pre-dispensing order, the caller must first reinstate it. Recordscancelled_by,cancellation_reason, andcancelled_at; all immutable.cancelled_byandreasonmust each be non-empty and non-whitespace-only (invalid-request).already-dispensedcovers Dispensed and Administered states — usediscontinuefor orders that have been dispensed. -
discontinue(order_id, discontinued_by, reason) → discontinued | rejected(not-known | on-hold | already-amended | already-cancelled | already-discontinued | already-completed | not-dispensed | invalid-request | storage-failure)— terminate the order after dispensing has begun. Valid only for orders in Dispensed or Administered state. To discontinue a held post-dispensing order, the caller must first reinstate it. Recordsdiscontinued_by,discontinuation_reason, anddiscontinued_at; all immutable.discontinued_byandreasonmust each be non-empty and non-whitespace-only (invalid-request).not-dispensedcovers Ordered and Verified states — usecancelfor orders that have not been dispensed. -
read(query) → ordered_sequence_of_orders | rejected(invalid-query)— return orders matching the query, ordered byordered_atascending. A query may filter byorder_id,patient_ref,medication_ref,prescriber_ref, state, time ranges onordered_at, or any combination. A time range filter onordered_attakes the form{after: <timestamp>, before: <timestamp>}with both sub-keys optional;afteris an inclusive lower bound andbeforeis an inclusive upper bound. A query supplying only anorder_idreturns at most one order. A well-formed query matching no orders returns an empty sequence, not a rejection. A query with no filters returns every order in the store. Only malformed parameters surface asinvalid-query: a syntactically invalidorder_id(non-null, non-empty), an unrecognized state value, or a time range with end before start.
Outputs
- For
order: a freshorder_id, or a rejection. - For
amend: a freshorder_idfor the successor order, or a rejection. - For
verify,hold,reinstate,dispense,administer,complete,cancel,discontinue: the named outcome token (verified,held,reinstated,dispensed,administered,completed,cancelled,discontinued), or a rejection. - For
read: a (possibly empty) ordered sequence of orders. Each order carries its full field set for its current state. The core fields present on every order are:order_id,patient_ref,prescriber_ref,medication_ref,dose,dose_unit,route,frequency,duration(if bounded),clinical_evidence_ref(if supplied),ordered_at, andstate. State-specific field groups are cumulative: once a group is written by a transition, it persists on the order record in all subsequent states regardless of further transitions, including transitions to On Hold, terminal states, or Amended. The state in which each group first appears is the earliest state from which that group is readable. Amendment fields (predecessor_id,amended_by,amendment_reasonon a successor;successor_idon an Amended original) — first present whenamendcompletes. Verification fields (verifier_ref,verified_at) — first present at Verified; persist through Dispensed, Administered, Completed, Discontinued (if dispensed), On Hold (whenprior_stateis Verified or a later state), and Amended (when amended from Verified state). Hold fields (held_by,hold_reason,held_at,prior_state) — present on any order that has been held, including orders currently On Hold (most recent hold only; full history requires Event Log). Reinstate fields (reinstated_by,reinstated_at) — present on orders that have been reinstated at least once (most recent reinstate only; full history requires Event Log). Dispense fields (dispenser_ref,quantity,lot_number,dispensed_at) — first present at Dispensed; persist through Administered, Completed, Discontinued, and On Hold (whenprior_stateis Dispensed, Administered, or a later state). Administration fields (administerer_ref,administered_at) — first present at Administered; persist through Completed, Discontinued (if administered before discontinuation), and On Hold (whenprior_stateis Administered). Completion fields (completed_by,completed_at) — present on Completed orders only. Cancellation fields (cancelled_by,cancellation_reason,cancelled_at) — present on Cancelled orders only. Discontinuation fields (discontinued_by,discontinuation_reason,discontinued_at) — present on Discontinued orders only. The combinations follow mechanically from the state transitions; a Completed order carries verification, dispense, and administration field groups simultaneously, and an On Hold order from Dispensed state carries verification and dispense field groups alongside the hold fields.
State
Each order is in exactly one state:
- Ordered — the order has been placed and awaits pharmacist verification. May be verified, amended, held, or cancelled.
- Verified — a pharmacist has reviewed and cleared the order for dispensing. Carries
verifier_refandverified_at(immutable). May be dispensed, amended, held, or cancelled. - Amended — the order has been superseded by a successor. Retained and visible; carries
successor_idpointing to the correcting order. No further transitions from Amended. The successor carriespredecessor_id,amended_by, andamendment_reason(all immutable from the momentamendcompletes). - On Hold — the order has been temporarily suspended. Carries
prior_state(the state before the hold),held_by,hold_reason, andheld_at. May only be reinstated (returning toprior_state); all other state-changing actions are rejected. - Dispensed — the pharmacy has prepared and released the medication. Carries
dispenser_ref,quantity,lot_number(if recorded), anddispensed_at(all immutable). May be administered, held, or discontinued. - Administered — at least one dose has been given to the patient. Carries
administerer_refandadministered_at(immutable). May be completed, held, or discontinued. - Completed — the full course has been administered. Carries
completed_byandcompleted_at(immutable). Terminal; no further transitions. - Cancelled — the order was terminated before any dispensing. Carries
cancelled_by,cancellation_reason, andcancelled_at(immutable). Terminal; no further transitions. - Discontinued — the order was terminated after dispensing had begun. Carries
discontinued_by,discontinuation_reason, anddiscontinued_at(immutable). Terminal; no further transitions.
Valid transitions:
- Ordered → Verified (via
verify) - Ordered → Amended (via
amend; successor starts Ordered) - Ordered → On Hold (via
hold;prior_state: Ordered) - Ordered → Cancelled (via
cancel) - Verified → Dispensed (via
dispense) - Verified → Amended (via
amend; successor starts Ordered) - Verified → On Hold (via
hold;prior_state: Verified) - Verified → Cancelled (via
cancel) - On Hold → prior_state (via
reinstate) - Dispensed → Administered (via
administer) - Dispensed → On Hold (via
hold;prior_state: Dispensed) - Dispensed → Discontinued (via
discontinue) - Administered → Completed (via
complete) - Administered → On Hold (via
hold;prior_state: Administered) - Administered → Discontinued (via
discontinue)
Successor orders created by amend always start in Ordered state, regardless of whether the original was Ordered or Verified. A purged or deleted state does not exist in this atom. Retention and eventual destruction belong to composing patterns (Retention Window, Legal Hold).
Flow
- Prescriber places the order. Calls
order(patient_ref: "p77", prescriber_ref: "dr_osei", medication_ref: "med-lisinopril-10mg", dose: 10, dose_unit: "mg", route: "oral", frequency: "QD", duration: 30). The atom assignsorder_id, setsstate = Ordered, recordsordered_at. Returnsorder_id. - Pharmacist reviews and clears. Calls
verify(order_id, verifier_ref: "pharm_wu"). Recordsverifier_refandverified_at, transitions to Verified. Returnsverified. - Pharmacy dispenses. Calls
dispense(order_id, dispenser_ref: "tech_jones", quantity: 30). Records dispense fields, transitions to Dispensed. Returnsdispensed. - Nurse administers the first dose. Calls
administer(order_id, administerer_ref: "nurse_kim"). Records administration fields, transitions to Administered. Returnsadministered. - Course completes. Calls
complete(order_id, completed_by: "nurse_kim"). Records completion fields, transitions to Completed. Returnscompleted.
Alternate paths: prescriber amends before dispensing (creates successor in Ordered); order held for surgery then reinstated; order cancelled before dispensing; order discontinued after dispensing begins.
Decision points
-
At
order—patient_ref,prescriber_ref, andmedication_refmust each contain at least one non-whitespace character;dosemust be a positive number;dose_unit,route, andfrequencymust each contain at least one non-whitespace character;duration, if supplied, must be a positive number;clinical_evidence_ref, if supplied, must contain at least one non-whitespace character;ordered_at, if supplied, must not be in the future (checked against the receiving node’s wall clock). Any violation rejects asinvalid-order.storage-failureif the store write fails after all preconditions pass; noorder_idis issued and no record enters the store. -
At
amend—not-knownif theorder_iddoes not exist;on-holdif the order is On Hold (reinstate first);already-amendedif Amended;already-cancelledoralready-discontinuedif terminal;already-dispensedif Dispensed, Administered, or Completed. If none of the above:amended_bymust be non-empty and non-whitespace-only,reasonmust be non-empty and non-whitespace-only — either failing isinvalid-request. At least one supplied dosing parameter must differ from the original’s current values — an amend that changes nothing isinvalid-request. The change-detection check treats an absent parameter (not supplied in the call) as “keep the original value” and an explicitly nildurationas “remove the duration, converting the order to open-ended.” Settingdurationto nil when the original has a duration is therefore a valid change. Settingdurationto nil when the original already has no duration is not a change and is rejected asinvalid-requestif it is the only parameter supplied. If either the successor creation or the original’s state update cannot be made durable,rejected(storage-failure)and no observable state change occurs: the successor is not created and the original remains in its prior state. Seeamendtwo-write atomicity in Edge cases. -
At
verify—not-known;on-hold;already-amended,already-cancelled,already-discontinued,already-completed(terminal/inactive);not-in-ordered-statefor Verified, Dispensed, and Administered states — the order has already been verified or has progressed beyond the verification stage.verifier_refmust be non-empty and non-whitespace-only (invalid-request).storage-failureif the state update cannot be made durable; order remains Ordered. -
At
hold—not-known;already-on-hold;already-completed,already-cancelled,already-discontinued,already-amended(terminal/inactive). Valid source states: Ordered, Verified, Dispensed, Administered.held_byandreasonmust each be non-empty and non-whitespace-only (invalid-request).storage-failureleaves the order’s state unchanged. -
At
reinstate—not-known;not-on-holdfor any non-On Hold state.reinstated_bymust be non-empty and non-whitespace-only (invalid-request). Reinstates to the state stored inprior_state— the target state is not a parameter.storage-failureleaves the order On Hold. -
At
dispense—not-known;on-hold;already-amended,already-cancelled,already-discontinued,already-completed(terminal/inactive);not-verifiedfor Ordered state — an unverified order may not be dispensed;already-dispensedfor Dispensed and Administered states.dispenser_refmust be non-empty and non-whitespace-only;quantitymust be strictly positive; either failing isinvalid-request.lot_number, if supplied, must be non-empty and non-whitespace-only.storage-failureleaves the order Verified. -
At
administer—not-known;on-hold;already-amended,already-cancelled,already-discontinued,already-completed(terminal/inactive);not-dispensedfor Ordered and Verified states (Amended orders returnalready-amendedat higher priority and do not reach this check);already-administeredfor Administered state.administerer_refmust be non-empty and non-whitespace-only (invalid-request).storage-failureleaves the order Dispensed. -
At
complete—not-known;on-hold;already-amended,already-cancelled,already-discontinued,already-completed(terminal/inactive);not-administeredfor Ordered, Verified, and Dispensed states.completed_bymust be non-empty and non-whitespace-only (invalid-request).storage-failureleaves the order Administered. -
At
cancel—not-known;on-hold(reinstate first to surface the order’s lifecycle position before terminating it — see Invariant 9 and Behavior);already-amended,already-cancelled,already-discontinued,already-completed(terminal/inactive);already-dispensedfor Dispensed or Administered states — usediscontinueinstead. Valid source states: Ordered, Verified.cancelled_byandreasonmust each be non-empty and non-whitespace-only (invalid-request).storage-failureleaves the order’s state unchanged. -
At
discontinue—not-known;on-hold(reinstate first);already-amended,already-cancelled,already-discontinued,already-completed(terminal/inactive);not-dispensedfor Ordered, Verified, and Amended states — usecancelinstead. Valid source states: Dispensed, Administered.discontinued_byandreasonmust each be non-empty and non-whitespace-only (invalid-request).storage-failureleaves the order’s state unchanged. -
At
read— any suppliedorder_idmust be syntactically valid (non-null, non-empty). Any supplied state filter must name one of the nine valid states. A time range filter onordered_atmust haveafter≤beforewhen both are supplied; a range withafter>beforeisinvalid-query. A query with no filters is well-formed. A well-formed query matching no orders returns an empty sequence, not a rejection. Only malformed parameters surface asinvalid-query.
Behavior
- Orders are durable on success. Once
orderreturns anorder_id, the order is in the store and will appear in subsequent reads. - Amendment is additive, not destructive.
amendcreates a new order record; the original is retained in Amended state. Both are visible toread; queries filtering for non-Amended states return only active orders. - The successor always starts in Ordered state. An amendment to a Verified order produces a successor requiring fresh pharmacist verification before dispensing. The original Verified order’s
verifier_refandverified_atremain on the Amended original and do not transfer to the successor. - Hold is reversible; reinstate returns to prior_state.
prior_stateis set at hold time and determines where reinstate returns. No action other thanreinstate(andread) is valid against an On Hold order. cancelanddiscontinuerequire reinstate before acting on held orders. This is deliberate friction: a held order’s lifecycle position is suspended. Explicitly reinstating it (acknowledging where in the lifecycle the order stands) before terminating it prevents accidental termination of orders paused for procedural reasons.- Terminal states are absorbing. Completed, Cancelled, and Discontinued orders accept no further state transitions. Amended orders are similarly inactive.
- Reads are repeatable; the underlying store is monotonic. The order store only grows. An unfiltered read at
t2 > t1returns every order visible att1plus any added in between. State-filtered reads are not monotonic: an order visible att1under a given state filter may be absent att2if it transitioned.
Feedback
- After
order— a new Ordered record exists;order_id, core fields, andordered_atare set and immutable. - After
amend— the original is now Amended (acquiressuccessor_id); a new Ordered successor exists withpredecessor_id,amended_by, andamendment_reasonset and immutable. The original’s core fields are unchanged. - After
verify— the order is now Verified;verifier_refandverified_atare set and immutable. - After
hold— the order is now On Hold;prior_state,held_by,hold_reason, andheld_atare set. - After
reinstate— the order is now in the state named byprior_state;reinstated_byandreinstated_atare set. They reflect the most recent reinstate; a subsequent hold/reinstate cycle will overwrite them — see Invariant 12 and Multiple hold cycles in Edge cases. - After
dispense— the order is now Dispensed;dispenser_ref,quantity,lot_number(if supplied), anddispensed_atare set and immutable. - After
administer— the order is now Administered;administerer_refandadministered_atare set and immutable. - After
complete— the order is now Completed;completed_byandcompleted_atare set and immutable. - After
cancel— the order is now Cancelled;cancelled_by,cancellation_reason, andcancelled_atare set and immutable. - After
discontinue— the order is now Discontinued;discontinued_by,discontinuation_reason, anddiscontinued_atare set and immutable.
Each rejected action produces an observable refusal naming the failed precondition.
Invariants
-
Invariant 1 — Order immutability. After a successful
order, the fieldsorder_id,patient_ref,prescriber_ref,medication_ref,dose,dose_unit,route,frequency,duration,clinical_evidence_ref, andordered_atnever change, regardless of any subsequent actions. -
Invariant 2 — Successor inherits identity fields. The successor created by
amendcarries the samepatient_refandmedication_refas the original, by construction:amenddoes not accept either as a parameter, making divergence structurally impossible.prescriber_refis also inherited;amended_byrecords who made the amendment, but prescribing authorship belongs to the original prescriber. A clinician who needs to change the medication must cancel the original and place a new order. -
Invariant 3 — Amendment is pre-dispensing only.
amendis rejected for any order in Dispensed, Administered, Completed, On Hold, Cancelled, Discontinued, or Amended state. An order that has crossed the dispensing boundary requires discontinuing and reordering, not amendment, because the medication has left the pharmacy’s custody. -
Invariant 4 — Amendment chains are linear. Each order has at most one
successor_idand at most onepredecessor_id. Amendment chains are singly-linked; branching is not permitted. An already-Amended order rejectsamendwithalready-amended. -
Invariant 5 — Hold carries prior_state; reinstate returns to it. When
holdtransitions an order to On Hold, the current state is recorded asprior_state.reinstatetransitions the order to the state named inprior_state— the atom does not accept a target state as a parameter, so deviation from the recorded prior state is structurally impossible. -
Invariant 6 — Cancel is pre-dispensing; discontinue is post-dispensing.
cancelis rejected for orders in Dispensed, Administered, or Completed state — usediscontinue.discontinueis rejected for orders in Ordered or Verified state — usecancel. This boundary is clinically and regulatorily load-bearing: a cancelled order (medication never reached the patient) has materially different implications for pharmacy accounting, DEA controlled-substance reconciliation, and adverse-event investigation than a discontinued order (medication was dispensed or administered but stopped). -
Invariant 7 — Terminal states are absorbing. An order in Completed, Cancelled, or Discontinued state accepts no further state transitions. Any action other than
readagainst such an order is rejected with the appropriate already-terminal reason. -
Invariant 8 — Amended state is inactive. An order in Amended state accepts no further state transitions. All actions other than
readagainst an Amended order are rejected withalready-amended. Clinical workflow continues on the successor. -
Invariant 9 — On Hold accepts only reinstate. An order in On Hold state accepts no state-changing actions other than
reinstate. All other state-changing actions returnon-hold. This enforces that an order’s lifecycle position is explicitly surfaced before any further action is taken. -
Invariant 10 — All actor references are required and non-whitespace. Every action that writes an actor attribution field requires the value to contain at least one non-whitespace character:
prescriber_refatorder;amended_byatamend;verifier_refatverify;held_byathold;reinstated_byatreinstate;dispenser_refatdispense;administerer_refatadminister;completed_byatcomplete;cancelled_byatcancel;discontinued_byatdiscontinue. Whitespace-only values are treated as empty and rejected asinvalid-request(orinvalid-orderfororder). Attribution is the core non-repudiation property of this atom; an empty actor reference undermines every regulated adversarial scenario. -
Invariant 11 — Reason fields are required and non-whitespace.
hold_reason(athold),cancellation_reason(atcancel),discontinuation_reason(atdiscontinue), andamendment_reason(atamend) must each contain at least one non-whitespace character. These reasons are the clinical and administrative explanations that make the record interpretable in audit, dispute, and forensic investigation. An empty reason defeats the audit trail the same way an empty actor reference does. -
Invariant 12 — Transition metadata is write-once, with two exceptions. Every field written by a state-transition action is immutable after that transition completes — with two related exceptions. First, a second
holdcall on an order that has been reinstated overwrites the prior hold fields (held_by,hold_reason,held_at,prior_state) with the new hold’s values. Second, a secondreinstatecall (following a second hold) overwrites the prior reinstate fields (reinstated_by,reinstated_at) with the new reinstate’s values. Neither is a violation of immutability in the per-transition sense: each individual hold and each individual reinstate transition writes its fields once and those fields are immutable until the next cycle. The order record carries the most recent hold’s and most recent reinstate’s metadata; a full hold/reinstate history requires composing with Event Log or Audit Trail (see Multiple hold cycles in Edge cases). All other transition metadata fields —verifier_ref,verified_at, all dispense fields, all administration fields, all completion/cancellation/discontinuation fields, all amendment chain fields — are written once and never change. -
Invariant 13 — ordered_at is set once.
ordered_atis set atordertime (from the supplied value or the receiving node’s wall clock) and never changes. The successor order created byamendcarries its ownordered_at, reflecting when the amendment was placed. -
Invariant 14 — Order store durability. No
order_idis removed from the store. State transitions never destroy records. The order count is monotonically non-decreasing for the lifetime of the store instance, and the store admits no deletion surface by spec. Astorage-failureresponse from any action guarantees that no partial record or partial state change is observable: the action either makes all required writes durable or has no observable effect. An implementation that returnsstorage-failurewhile leaving a partial record visible is non-conforming.
Examples
Happy path — inpatient order through completion
A physician orders a blood pressure medication: order(patient_ref: "p77", prescriber_ref: "dr_osei", medication_ref: "med-lisinopril-10mg", dose: 10, dose_unit: "mg", route: "oral", frequency: "QD", duration: 30) → order_id: "ord-001". The clinical pharmacist verifies: verify("ord-001", verifier_ref: "pharm_wu") → verified. The pharmacy tech dispenses: dispense("ord-001", dispenser_ref: "tech_jones", quantity: 30, lot_number: "LOT-2026-A") → dispensed. The morning nurse administers the first dose: administer("ord-001", administerer_ref: "nurse_kim") → administered. After 30 days: complete("ord-001", completed_by: "nurse_kim") → completed. The order now carries all five attribution fields — prescriber, verifier, dispenser, administerer, completer — each immutable.
Amendment — dose correction before dispensing
The physician realizes the dose should be 5mg before the pharmacist has dispensed. Calls amend("ord-001", amended_by: "dr_osei", dose: 5, reason: "prescribing error — weight-based dose is 5mg, not 10mg") → order_id: "ord-002". The store now contains ord-001 (Amended, successor_id: "ord-002") and ord-002 (Ordered, predecessor_id: "ord-001", dose 5mg, amended_by: "dr_osei", amendment_reason: "prescribing error..."). The pharmacist receives ord-002 for verification. A query for non-Amended orders returns only ord-002; the audit record preserves both the original dose and the correction.
Hold and reinstate — surgical pause
An order for warfarin (anticoagulant) is Verified. Before dispensing, the patient is scheduled for surgery. Nurse calls hold("ord-003", held_by: "nurse_chen", reason: "surgical hold — patient NPO, anticoagulation contraindicated per surgical consult") → held. prior_state: Verified is recorded. After surgery: reinstate("ord-003", reinstated_by: "nurse_chen") → reinstated. The order returns to Verified and is again eligible for dispensing.
Rejection path — amendment attempted after dispensing
The pharmacy has already dispensed ord-001. The prescriber attempts to correct the dose: amend("ord-001", amended_by: "dr_osei", dose: 5, reason: "dose correction") → rejected(already-dispensed). The prescriber must instead discontinue the active order and place a new one with the corrected dose. This is an intentional constraint: a dose change after the medication has left the pharmacy cannot be undone by amending the record — the physical medication in the patient’s possession exists at the original dose.
Rejection path — cancel attempted after dispensing
A prescriber calls cancel("ord-001", cancelled_by: "dr_osei", reason: "no longer needed") against an order in Dispensed state → rejected(already-dispensed). For an order that has left the pharmacy, discontinue is the correct action. The distinction matters for DEA accounting: a cancelled order implies no medication was ever dispensed; a discontinued order implies medication was dispensed and must be reconciled.
Rejection path — dispense without verification
A pharmacy system attempts to dispense an order still in Ordered state: dispense("ord-005", dispenser_ref: "tech_jones", quantity: 30) → rejected(not-verified). No medication is released; the pharmacist must verify the order before any dispensing occurs.
Rejection path — action against an on-hold order
A physician attempts to amend an order while it is on hold: amend("ord-006", amended_by: "dr_osei", dose: 5, reason: "dose correction") → rejected(on-hold). The order must be reinstated first. This enforces that the lifecycle position is explicitly acknowledged — the prescriber must surface whether the hold is still appropriate before modifying the order.
Regulated adversarial scenarios
Regulator audit — DEA controlled substance prescription trail
A DEA auditor investigating Schedule II controlled substance dispensing requests the complete lifecycle history for a specific order. Queries read({order_id: "ord-cs-017"}). The result must show: the prescriber (prescriber_ref, ordered_at) — immutable by Invariant 1; the pharmacist who verified (verifier_ref, verified_at) — immutable by Invariant 12; the dispenser (dispenser_ref, quantity, lot_number, dispensed_at) — immutable by Invariant 12; and the administerer (administerer_ref, administered_at) — immutable by Invariant 12. If the order was amended before dispensing, the amendment chain — original (Amended, with successor_id), intermediate orders, and the final dispensed successor — is traceable via predecessor_id / successor_id links, with each link’s amended_by and amendment_reason immutable by Invariant 12. No gap in the chain is permitted. The audit clears when the records alone account for every controlled unit: who prescribed, who cleared, who released, and who administered — without recourse to developer testimony, runbooks, or log integrity.
Disputed order — wrong medication or wrong dose alleged
A patient alleges they were administered a different medication than prescribed, or a dose different from what their physician ordered. The investigator queries the order record for ord-022. Invariant 1 guarantees medication_ref is immutable — it cannot have been edited to cover the discrepancy. The dispenser record (dispenser_ref, quantity, dispensed_at) and the administration record (administerer_ref, administered_at) are both immutable by Invariant 12. If there is an amendment chain, every amendment carries amended_by and amendment_reason (immutable by Invariant 12), and the ordering of events is deterministic via the predecessor_id / successor_id chain and ordered_at timestamps. The dispute is answered from the records alone: the medication identity, dose, attributing actors, and timing are all permanently fixed, and no field can have been retroactively altered.
Breach investigation — controlled substance diversion
An internal audit detects a quantity discrepancy: a controlled substance lot appears dispensed but no administration record exists for the corresponding order. The investigator queries read({medication_ref: "med-oxycodone-5mg"}) across the date range and filters for orders in Dispensed state. The result surfaces orders that have reached Dispensed but not Administered or Completed. For each such order, dispenser_ref and quantity are on record and immutable by Invariant 12 — the dispenser attribution cannot have been edited after the fact. The absence of an administer transition on an order that was dispensed is itself a forensic signal. If the order was discontinued without administration, discontinued_by (required non-empty by Invariant 10) and discontinuation_reason (required non-empty by Invariant 11) must both be present and immutable — an unexplained discontinuation with no actor or no reason is a conformance failure. The investigation has the dispenser identity, the dispensing timestamp, the lot number, and the quantity; the audit trail either closes the chain or names the gap.
Generation acceptance
Any implementation derived from this atom must produce records and a runtime surface that pass the following checks from the records alone, without recourse to source code, runbooks, or developer narration:
-
Core field immutability check. For a known
order_id, retrieve the order at two different times and compare all core fields.order_id,patient_ref,prescriber_ref,medication_ref,dose,dose_unit,route,frequency,duration,clinical_evidence_ref, andordered_atmust be identical in both reads. Any transition-metadata field that is set in either read must hold the same value in any later read where it is present. A transition-metadata field that changes between two reads (other than hold fields overwritten by a subsequent hold cycle, per Invariant 12) is a conformance failure. -
Amendment chain integrity check. For a known Amended order, retrieve its
successor_idand confirm the successor exists, carries apredecessor_idequal to the original’sorder_id, and shares the samepatient_refandmedication_refas the original. Confirmamended_byandamendment_reasonare non-empty on the successor. Confirm that the original’sverifier_refandverified_atare NOT present on the successor — the original’s verification does not transfer; if the successor carriesverifier_ref, it must have been set by a subsequentverifycall using the successor’s ownorder_id(verifiable by confirming the successor has been in Verified or a downstream state). -
Terminal state finality check. Attempt a state-changing action (
verify,dispense,hold,cancel, ordiscontinue) against a known Completed, Cancelled, and Discontinued order respectively. All calls must return the appropriate already-terminal rejection. Confirm each order’s fields are unchanged after the attempted action. -
Pre-dispensing amendment boundary check. Attempt
amendagainst a known Dispensed order. The call must returnrejected(already-dispensed). Confirm no successor order was created and the original’s state is unchanged. -
Role attribution completeness check. For every order in the store: confirm
prescriber_refis non-empty. For every order currently carryingverifier_ref(any order whose record includes this field, regardless of current state — including On Hold orders that were verified before being held, and terminal orders that passed through Verified): confirmverifier_refis non-empty. For every order currently carryingdispenser_ref: confirmdispenser_refis non-empty andquantityis positive. For every order currently carryingadministerer_ref: confirmadministerer_refis non-empty. Additionally, for every order in Dispensed, Administered, or Completed state: confirmverifier_refis present — these states are only reachable via the Verified state, so a missingverifier_refis a conformance failure regardless of how the audit is timed. An order missing a required attribution field is a conformance failure. -
No-destruction check. For a set of
order_ids known to have been issued — including Amended, Cancelled, and Discontinued ones — confirm thatreadreturns each of them when queried byorder_idacross all states. No issued id may be absent from the store.
Edge cases and explicit non-goals
-
Amending to remove duration. Setting
durationto nil in anamendcall converts a duration-bounded order to an open-ended one; this counts as a change and is valid. The reverse — supplying adurationon an amendment when the original had none — is also valid. Open-ended orders that have been amended to be bounded must be explicitly completed or discontinued when the course ends. -
Multiple hold cycles. An order may be held and reinstated more than once. Each
holdcall overwrites the prior hold fields on the order record (held_by,hold_reason,held_at,prior_state) with the new values; eachreinstatecall overwrites the prior reinstate fields (reinstated_by,reinstated_at) with the new values. The order record carries the most recent hold’s metadata and the most recent reinstate’s metadata. A complete history of every hold and reinstatement event requires composing with Event Log or Audit Trail, which capture every state transition as an immutable event. This behavior is consistent with Invariant 12’s “write-once per transition” framing — each hold and each reinstate is its own transition that writes its fields once. -
amendtwo-write atomicity. Theamendoperation requires two durable writes: creating the successor order and updating the original to Amended state with asuccessor_id. A crash between writes leaves the store inconsistent — either a successor exists without the original pointing to it, or the original is marked Amended with asuccessor_idthat does not exist (both violate Invariant 4). Implementations must provide atomic transaction support across both writes, or a crash-recovery scan that detects and repairs dangling amendment links on restart. Astorage-failureresponse is the observable signal of an aborted two-write attempt; per Invariant 14, no partial record is visible after such a response. -
Multi-dose regimens. The
administeraction transitions the order from Dispensed to Administered on the first recorded administration and returnsalready-administeredon any subsequent call. For multi-dose regimens (daily medication for 30 days, weekly chemotherapy), individual dose events beyond the first are not modeled by this atom. Individual dose event tracking is a composing concern: a Medication Administration Record layer composed with Event Log captures each subsequent dose. This atom tracks the order’s lifecycle state; the individual-dose surface belongs to the composing layer. -
orderidempotency.orderis not idempotent. A prescriber system that retries after a network timeout creates a duplicate order if the first call succeeded; both calls return distinctorder_ids. For at-most-once semantics on order submission, compose with Duplicate Prevention. DEA EPCS two-factor attestation requirements belong to Actor Identity. -
Entered-in-error orders. An order placed by mistake (wrong patient, system glitch, duplicate submission) should be cancelled with a reason identifying it as an entry error. The atom has no separate
entered-in-errorstate;cancelwith an appropriate reason is the mechanism. Thecancellation_reasonfield carries the semantic distinction between a clinical decision and a clerical correction. For controlled substances, entered-in-error cancellations may carry additional DEA reporting obligations; those belong to a DEA-reporting composing pattern. -
Refills. Outpatient prescriptions often carry refill counts. A refill is a new dispensing event against a prior prescription. This atom does not model refills; each refill would require either a new order or a composing layer on top of this atom. The atom closes at Completed or Discontinued.
-
Access control. Who may place, verify, dispense, administer, or terminate an order is not defined by this atom. That is the obligation of a composing Permissions pattern. DEA prescriber-authorization and pharmacist-licensure checks are access-control concerns.
-
Controlled substance schedule. Whether
medication_refrefers to a DEA-scheduled substance, and the regulatory obligations that attach (DEA registration, EPCS two-factor, refill restrictions, quantity limits), are not modeled by this atom.medication_refis opaque. Deployments handling controlled substances compose with appropriate regulatory controls. -
Retention and destruction. The atom retains all orders indefinitely. Retention under HIPAA (US Health Insurance Portability and Accountability Act) and applicable state law, and eventual defensible destruction, belong to Retention Window and Legal Hold.
-
Tamper-evidence. The atom guarantees immutability by spec; it does not cryptographically prevent a store administrator from rewriting records. Compose with Tamper Evidence for cryptographic guarantees. DEA EPCS non-alteration requirements are satisfied at the layer Tamper Evidence provides.
-
Concurrency. Two systems concurrently calling
verifyon the same order, ordispenseafter concurrent verifications, is not handled at this layer. Implementations must serialize state transitions on a givenorder_id. -
Clock semantics.
ordered_atand all_attimestamp fields default to the receiving node’s wall clock when not supplied. The future-timestamp restriction applies only toordered_at— a prescription cannot logically be dated in the future. All other_atfields (verified_at,dispensed_at,administered_at,completed_at,cancelled_at,discontinued_at,held_at,reinstated_at) accept caller-supplied values including back-dated ones, with no look-back limit imposed by this atom. Back-dating is normal in clinical documentation: a nurse charting a dose administered six hours earlier, or a pharmacist recording a dispense that occurred before the system was available, produces a back-dated timestamp that the atom accepts. Clock skew, timezone normalization (storage in UTC), and monotonicity are deployment concerns. When two or more orders share the sameordered_at, the relative order in areadresult is implementation-defined but must be stable across consecutive reads of the same store state. -
Rejection priority. When multiple precondition violations exist on the same call, the rejection returned follows a defined priority:
not-known(id existence) →on-hold(for actions that reject on hold) →already-amended/already-cancelled/already-discontinued/already-completed(terminal/inactive states) → state-specific rejections (not-in-ordered-state,not-verified,not-dispensed,not-administered,already-dispensed,already-administered,already-on-hold) →invalid-request(actor references, reason fields, content) →storage-failure(persistence). This order is the same across conforming implementations.
Composition notes
Medication Order composes naturally with the existing library:
- Actor Identity —
prescriber_ref,verifier_ref,dispenser_ref,administerer_ref, and the various_byfields are opaque references; Actor Identity provides cryptographic attestation that those references are real, credentialed actors who authorized their respective actions. DEA EPCS two-factor attestation at prescribe time is the Actor Identity composition for controlled-substance orders; it converts this atom’s attribution fields from trusted assertions to non-repudiable proofs. - Clinical Observation — a medication order is often placed in response to a clinical observation (elevated blood pressure → antihypertensive order; abnormal lab result → treatment initiation). The optional
clinical_evidence_reffield carries an opaque reference to the observation(s) that informed the prescribing decision. Clinical Observation provides the upstream substrate; Medication Order carries the downstream response. The relationship is advisory —clinical_evidence_refis opaque metadata on the order, not a structural dependency. Clinical Observation’s Composition notes identified Medication Order as a forthcoming pattern that “consumes Clinical Observation as evidence”; this is the concrete form that relationship takes. - Tamper Evidence — seals the order store against post-hoc modification, complementing the spec-level immutability guarantee with a cryptographic one. DEA EPCS non-alteration requirements are satisfied at this layer.
- Retention Window — governs the minimum retention period for medication order records under HIPAA (generally six years for adult records, longer for pediatric records, with state variation).
- Audit Trail — the canonical composition for regulated record-keeping; Medication Order feeds it. Every state transition is an auditable event.
- Event Log — provides the substrate for capturing individual dose events in multi-dose regimens and a complete hold/reinstate history across multiple hold cycles.
- Permissions — governs who may place, verify, dispense, administer, and terminate orders; composes access control onto this atom’s attribution model.
- Duplicate Prevention — for at-most-once semantics on order submission, preventing duplicate orders from network retries.
- Forthcoming: Care Plan — a composition modeling a structured set of medication orders, clinical observations, and clinical goals; Medication Order is a constituent.
Standards references
- HIPAA §164.312(b) — audit controls: covered entities must implement mechanisms to record and examine activity in systems containing ePHI (electronic Protected Health Information — individually identifiable health data in digital form). The order record, with its immutable attribution fields at every lifecycle stage, is the primary audit surface.
- HL7 FHIR MedicationRequest resource — the canonical interoperability representation of a medication order. This atom’s core fields map to FHIR’s
subject(patient_ref),requester(prescriber_ref),medication[x](medication_ref),dosageInstruction(dose, dose_unit, route, frequency, duration),authoredOn(ordered_at), andstatus(active → Ordered/Verified; on-hold → On Hold; cancelled → Cancelled; stopped → Discontinued; completed → Completed). FHIR separates MedicationRequest, MedicationDispense, and MedicationAdministration into three resources; this atom models the full lifecycle in one record — a deliberate choice that prioritizes attribution traceability over FHIR’s resource decomposition. FHIR’s MedicationRequest carries many additional fields (encounter, reasonCode, substitution, priorPrescription) not present here; those are composing-layer concerns. - DEA 21 CFR Part 1306 — prescription requirements for Schedule II–V controlled substances: prescriber DEA registration, patient identification, medication and quantity, directions for use, Schedule II refill prohibition.
prescriber_refandmedication_refare the record substrate for Part 1306 compliance; DEA registration verification is a composing pattern. - DEA 21 CFR Part 1311 (EPCS) — Electronic Prescriptions for Controlled Substances: requires two-factor cryptographic authentication at order time. Actor Identity composing with this atom is the implementation surface.
- 21 CFR Part 11 — electronic records in FDA-regulated contexts; each state transition is a regulated electronic record event requiring attribution and timestamp.
- Joint Commission Medication Management standards (MM.04.01.01) — require that medication orders be complete, legible, and attributable. The immutable core fields and mandatory attribution fields satisfy these requirements structurally.
- ISMP (Institute for Safe Medication Practices) — prescribing safeguards including required order elements (drug name, dose, route, frequency) align with this atom’s mandatory fields; ISMP’s error-reporting surface is the motivation for the amendment audit trail.
- RxNorm / NDC / SNOMED CT — controlled vocabularies for
medication_ref; recommended deployment conventions for the opaque medication reference, not atom-level obligations.
Status
grounded (passed all required review passes and is stable enough to generate from) — foundation round, two human refinement rounds, and AI adversarial round (Torvalds X2) complete. Last full rescan: 2026-05-20.
Lineage notes
Regulated atom. Conventions — Regulated adversarial scenarios and Generation acceptance — inherited from the methodology directly (PRESSURE_TESTING.md), baked in from the first draft. Conventions are not re-derived from Clinical Observation or Actor Identity.
Pass 1 — Structural completeness (GRID). Three findings, all closed in-pattern.
- Store instance model absent. The atom referenced “the store” without defining whether one global store or multiple named instances are valid, and no action accepted
store_nameas a parameter or named instance selection as a routing concern. Fixed: added a Store instance model subsection to Structure, mirroring Clinical Observation and Event Log.order_iduniqueness is now explicitly scoped to a store instance;patient_refis noted as globally scoped; store instance selection is named as a deployment-routing concern and added to Edge cases. - Hold and reinstate metadata not in State field listing.
held_by,hold_reason,held_at,prior_state,reinstated_by,reinstated_atwere described in the Actions section but not listed as fields in the On Hold state description or in Outputs. The regulated adversarial scenarios and Generation acceptance check 1 both depend on hold attribution being durably recorded and readable from the order record. Fixed: all hold and reinstate fields added to the On Hold state description, to Outputs (per-record field list), and to Feedback afterholdandreinstate. - Multiple hold cycles field overwrite unstated. The spec was silent on what happens when an order is held, reinstated, then held again — whether each
holdcall accumulates a history or overwrites prior hold fields. Implementations could diverge. Fixed: Edge case Multiple hold cycles added, stating that eachholdoverwrites the prior hold fields on the order record and that a full hold history requires composing with Event Log or Audit Trail. Invariant 12 updated with an explicit carve-out for hold-field overwrite behavior, preserving the “write-once per transition” semantics while naming the exception honestly.
All nine GRID nodes resolved. No extractions.
Pass 2 — Conceptual independence (EOS). Clean. Two extraction candidates evaluated; both kept in-pattern. One composition boundary judgment recorded.
dispenseandadministerextraction candidate. The dispensing and administration sub-actions map to FHIR’s separate MedicationDispense and MedicationAdministration resources and could be separate atoms. Evaluated: in this model, dispensing and administration are state transitions on the order record, not independent entities with their own identities or lifecycles. They do not have freestanding state machines — the dispenser and administerer records only make sense relative to the order they act on. A separate MedicationDispense atom would require the order’s identity to specify it, inverting the composition direction. Kept in-pattern. Noted: if a second domain in the library requires generic “material-issuance” or “care-delivery” mechanics independent of a prescription context, that recurrence may motivate extraction.- Amendment chain mechanics extraction candidate. Same argument as Clinical Observation’s Pass 2 evaluation. A generic “Supersession Chain” atom still loses: the fields operated on (
medication_ref,patient_refas non-amendable;dose,route,frequency,durationas correctable) are order-specific; the invariants name specific fields; a generic chain depends on the host for its constraints. Kept in-pattern. clinical_evidence_refabsorption check. An optional opaque reference; the atom does not interpret it, does not import Clinical Observation’s lifecycle, and does not name Clinical Observation in its specification. Clean.
Pass 3 — Adversarial scrutiny (Linus mode). Eight findings: six real, two minor. All closed in-pattern.
- Successor starts in Ordered regardless of original state — not stated. An amendment to a Verified order would plausibly produce a Verified successor if the spec was read quickly — the pharmacist had already verified, so why would the successor need re-verification? The spec never stated that the successor always starts in Ordered. Resolved: explicit statement added to the
amendAction, the State section (successor orders start in Ordered), and Behavior. The rationale — the amendment changes the clinical content and requires fresh pharmacist review — is stated inline. Also noted: the original Verified order’sverifier_refandverified_atremain on the Amended original and do not transfer to the successor. cancelanddiscontinuefrom On Hold — design decision not stated. Should a clinician be able to cancel a held pre-dispense order directly, or must they reinstate first? The spec namedon-holdas a rejection for both but did not state the rationale. Without an explanation, a reviewer would reasonably ask “why not just cancel it?”. Resolved: Behavior section adds the rationale explicitly — theon-holdrejection forcancelanddiscontinueis deliberate friction that prevents accidental termination of orders paused for procedural reasons; reinstating first surfaces the order’s lifecycle position and forces an explicit acknowledgment before termination.- Invariant 6 (cancel vs. discontinue boundary) not defended inline. The distinction was stated but not justified. A reader could view the two-action split as bureaucratic rather than load-bearing. Resolved: Invariant 6 adds the clinical and regulatory rationale inline — DEA controlled-substance reconciliation and adverse-event investigation both depend on the distinction between medication-never-dispensed (cancel) and medication-dispensed-but-stopped (discontinue). The invariant now reads as a defended claim, not a policy assertion.
already-amended,already-cancelled,already-discontinuedabsent from several action signatures.verify,dispense,administer, andcompleteoriginally listed only their state-specific rejection (not-in-ordered-state,not-verified,not-dispensed,not-administered) without naming terminal-and-inactive-state rejections that logically precede the state check in the priority order. A caller receivingnot-verifiedfor adispensecall against a Cancelled order would have a confusing diagnostic experience. Resolved: all four action signatures updated to include the terminal/inactive state rejections in the vocabulary; Decision points updated with the priority order stating these are checked before the state-specific rejections.already-cancelledabsent fromadministersignature. Following from the above, a Cancelled order would returnnot-dispensedfromadminister— technically accurate (cancelled orders were never dispensed) but semantically confusing to a caller expectingalready-cancelled. Resolved:already-cancelledadded toadminister’s signature and Decision point; in the priority order it is checked beforenot-dispensed.- Invariant 12 inconsistency with hold overwrite. The original Invariant 12 stated all transition metadata is write-once; but the Multiple hold cycles edge case (closed in Pass 1) stated that hold fields are overwritten on a second hold. The two claims were contradictory. Resolved: Invariant 12 rewritten to “write-once per transition, with one exception” — the exception for hold-field overwrite on subsequent hold cycles is named explicitly. The invariant preserves the core claim (per-transition immutability) while being accurate about the overwrite behavior.
ordernot defended as non-idempotent (minor). The spec was silent on whetherorderprovides at-most-once semantics under retry. A caller could assume retry-safety. Resolved: Edge caseorderidempotency added, naming the gap and pointing to Duplicate Prevention as the composing pattern. The framing follows Clinical Observation’s analogous edge case.amendtwo-write atomicity not named (minor). Same class of finding as Clinical Observation’s Pass 3. Resolved: Edge caseamendtwo-write atomicity added, naming the two-write requirement and mandating either atomic transaction support or a crash-recovery scan from implementations.
Refinement round 1 — re-run of all three passes. Five findings, all closed in-pattern. Round conducted with Grok’s structured review of the two foundation-round judgment calls (dispense/administer in-pattern, hold-field overwrite) plus a fresh re-running of all three passes.
-
Outputs description for hold fields incorrect (Pass 1). The Outputs section said hold fields are present “on orders that have been held and reinstated” — but hold fields are present on On Hold orders too, regardless of whether reinstate has been called. An On Hold order’s
held_by,hold_reason,held_at, andprior_stateare readable fromreadbefore any reinstate occurs. The phrasing implied the fields were only visible post-reinstate, which would make an On Hold order’s hold attribution invisible to a reader of the record. Resolved: Outputs updated to “on orders that have been held, including orders currently in On Hold state; reinstate fields on orders that have been reinstated at least once.” -
amendnil-duration vs. omitted-duration ambiguity (Pass 3). Theamendaction’s no-change check said “at least one supplied parameter must differ” without distinguishing between a parameter being absent (keep original value) and a parameter being explicitly nil (clear the value). Forduration, these have different meanings: absent means “leave the original duration unchanged”; nil means “remove the duration, making the order open-ended.” Anamendsupplying onlyduration: nilagainst an already-open-ended order is not a change and should beinvalid-request, but the spec was silent. Resolved: Decision point foramendupdated with an explicit statement of the absent-vs-nil distinction, naming the “nil on already-open-ended” case as a no-change rejection. -
Future-timestamp restriction applies only to
ordered_at— not stated (Pass 3). The Clock semantics edge case named theordered_atfuture-timestamp restriction but was silent on whetherdispensed_at,administered_at, and other_atfields have similar restrictions. A reader could infer the restriction applies everywhere. Clinical documentation workflows routinely back-date events (a nurse charting a dose administered six hours ago); the other_atfields must permit back-dating. Resolved: Clock semantics edge case updated to explicitly state that the future-timestamp restriction applies only toordered_at, that all other_atfields accept back-dated values with no look-back limit, and that back-dating is a normal clinical documentation workflow. -
Dispensing/administration scope decision not defended inline (Pass 3 / Grok review). The decision to model dispensing and administration as transitions on the order record rather than separate entities was documented in the foundation round’s Pass 2 Lineage notes but not in the atom’s main text. A reader of the Intent section alone would not encounter the rationale; it was a hidden decision visible only in the Lineage. Resolved: Intent section extended with a defended-in-line paragraph naming the FHIR decomposition as the alternative, stating the reason for the unified-record design (single auditable chain of custody, no freestanding state machines for dispense/administer), and naming the extraction trigger (a second domain with generic material-issuance semantics). Grok’s structured review confirmed the in-pattern judgment, specifically noting that FHIR’s three-resource decomposition serves broad interoperability while this atom prioritizes a tight, auditable primitive — a valid and often preferable trade-off for implementation-focused modeling.
-
holdaction not cross-referencing Invariant 12 (Pass 3 / Grok review). Theholdaction description referenced the Multiple hold cycles edge case but did not cite Invariant 12 by name, making it easy to miss the write-once-per-transition caveat and the hold-field overwrite exception. A reader of theholdaction alone could not discover the overwrite behavior without finding the edge case. Resolved:holdaction description updated to cite Invariant 12 explicitly alongside the edge case reference. Grok’s review validated the hold-field overwrite design: the behavior is explicit, honest (via Invariant 12), and aligns with the “expedient but auditable via composition” principle.
Pass 2 was clean. The dispense/administer extraction was re-examined with Grok’s independent review confirming the in-pattern judgment. The amendment chain extraction was re-examined and remains settled for the same reasons as in the foundation round. All five fixes are in-pattern resolutions; none required extraction or new composing patterns.
Refinement round 2 — re-run of all three passes. Five findings, all closed in-pattern.
-
Reinstate fields overwrite ambiguity (Pass 1 / Pass 3). Invariant 12 named only hold fields in its overwrite carve-out, while Feedback for
reinstatesaid “reinstated_byandreinstated_atare set and immutable.” By symmetry with hold fields — where the most recent hold’s metadata is operationally relevant and a second hold overwrites the prior values — reinstate fields should behave identically on a second reinstate cycle. The spec was silent, leaving conformance ambiguous: an implementation could plausibly retain the first reinstate’s values or overwrite them. Resolved: Invariant 12 extended from “one exception” to “two exceptions” naming reinstate fields alongside hold fields. Feedback forreinstateupdated to remove “and immutable” and explain the overwrite behavior with a cross-reference to Invariant 12. Outputs updated with “(most recent reinstate only; full history requires Event Log).” The behavior is consistent with the “expedient but auditable via composition” principle established for hold fields in Refinement round 1. -
Generation acceptance check 2 — successor state claim time-sensitive (Pass 1 / Pass 3). Check 2 said to confirm the successor “is in Ordered or a downstream state (never Verified or later unless re-verified on its own merits)” — a claim that depends on when the check is run. By the time an auditor runs this check, the successor may have already been verified and dispensed; “in Ordered state” would then be a false failure. The key invariant being checked — that the original’s Verified status does not transfer to the successor — is not captured by the current state at all; it belongs to whether
verifier_refis present on the successor and, if so, whether it was set by averifycall on the successor’s ownorder_id. Resolved: replaced the state claim with a field-based check: “confirm the original’sverifier_refandverified_atare NOT present on the successor — the original’s verification does not transfer.” This check is unambiguous regardless of when it runs. -
administerDecision point incorrectly lists Amended undernot-dispensed(Pass 3). The Decision point said “not-dispensedfor Ordered, Verified, and Amended states” — but per the Rejection priority, Amended orders returnalready-amendedbefore reaching thenot-dispensedcheck. ThecompleteDecision point already correctly omits Amended from itsnot-administeredlist. TheadministerDecision point was inconsistent with both the priority order and its siblingcomplete. Resolved: updated to “not-dispensedfor Ordered and Verified states (Amended orders returnalready-amendedat higher priority and do not reach this check).” -
Generation acceptance check 5 has blind spots for On Hold and terminal orders (Pass 3). Check 5 used “Verified state or beyond” / “Dispensed state or beyond” to determine which orders must carry attribution fields. This formulation misses On Hold orders (whose current state is On Hold, not Verified or Dispensed, but which may have been verified before being held) and terminal orders (whose current state is Cancelled or Discontinued but which may have passed through Verified or Dispensed). An On Hold order held from Verified state carries
verifier_refand any attribution check relying on “current state = Verified” would silently pass over it. Resolved: reformulated to field-based checks (“for every order currently carryingverifier_ref…”) supplemented by a state-based check for the provably necessary case (“for every order in Dispensed, Administered, or Completed state, confirmverifier_refis present — these states are only reachable via Verified”). This formulation is correct regardless of current state. -
dispensesignature missingalready-completed(Pass 3). Every other state-changing action that can be called against terminal orders includesalready-completedin its rejection vocabulary:hold,cancel,administer,complete,discontinueall carry it.dispensedid not. Withoutalready-completed, a Completed order hittingdispensefalls through the priority order past the terminal-state tier (sincealready-completedis not declared) and returnsalready-dispensed— technically accurate (a Completed order has been dispensed) but inconsistent with the priority order’s explicit terminal-state tier and with every other action’s behavior. The Decision point compounded this by listing “already-dispensed for Dispensed, Administered, or Completed state,” which was wrong — Completed orders should surfacealready-completedfirst. Resolved: addedalready-completedto thedispensesignature; updated thedispenseDecision point to includealready-completedin the terminal-state check tier and narrowalready-dispensedto Dispensed and Administered states only.
Pass 2 was clean. All five fixes are in-pattern resolutions. No extractions required.
AI adversarial round (Torvalds X2) — re-run of all three passes with fresh-reader discipline. Six findings; all closed in-pattern. Pass 2 clean.
-
prescriber_refnot documented as inherited by successor in Identity model (Pass 1). The Identity model explicitly stated “patient_refis inherited unchanged by any successor order created byamend” and “medication_refis inherited unchanged by any successor order created byamend” — butprescriber_refonly said “Set onorder, immutable. Amendments carry their ownamended_by; the originalprescriber_refis never changed.” That last clause describes the original, not the successor. A reader of the Identity model section who did not also read Invariant 2 would not know whether the successor inheritsprescriber_refor leaves it unset. Invariant 2 covered it, but the Identity model was inconsistent with its own pattern for the other two inherited reference fields. Resolved:prescriber_refdescription updated to explicitly state “inherited unchanged by any successor order created byamend,” parallel topatient_refandmedication_ref. -
Outputs field listing incomplete for On Hold and Discontinued orders with accumulated fields (Pass 1). The Outputs section listed “verification fields on Verified, Dispensed, Administered, and Completed orders” — omitting On Hold orders that were verified before being held, and Discontinued orders. Similarly “dispense fields on Dispensed, Administered, and Completed orders” omitted On Hold (from Dispensed or Administered) and Discontinued orders. “Administration fields on Administered and Completed orders” omitted On Hold (from Administered) and Discontinued (from Administered). The field listing was inaccurate for any order that transitioned to On Hold or Discontinued after accumulating fields. Resolved: Outputs field listing restructured around the cumulative principle — field groups are cumulative; once written by a transition they persist regardless of subsequent state changes — with the first-appearance state noted for each group and explicit examples of On Hold and Discontinued orders carrying accumulated field groups.
-
verifysignature missingalready-completed, inconsistent with Rejection priority (Pass 3). The Rejection priority edge case statesalready-completedis checked in the terminal-state tier before state-specific rejections and this order is “the same across conforming implementations.” Butverifydid not havealready-completedin its signature. A Completed order hittingverifywould fall through the terminal-state tier (noalready-completedto match) and surfacenot-in-ordered-state— technically accurate but inconsistent with the stated priority ordering, and inconsistent withhold,cancel,administer,complete, anddiscontinue, all of which carryalready-completed. Resolved:already-completedadded to theverifysignature;not-in-ordered-statedescription updated to cover Verified, Dispensed, and Administered states only. -
clinical_evidence_refvalidation silent when supplied as empty string (Pass 3). Every other reference field in the atom requires at least one non-whitespace character.clinical_evidence_refwas described as “optional” and “advisory” but the spec was silent on what happens if the caller supplies an empty or whitespace-only string. An implementation could accept it and store an empty field; another could silently drop it; a third could reject it — three divergent behaviors, all spec-compliant. Resolved:orderaction description updated to state “If supplied, it must contain at least one non-whitespace character; a supplied empty or whitespace-only value isinvalid-order. When absent, the field is not present on the order record; there is no nil-vs-absent distinction for this field.”orderDecision point updated to includeclinical_evidence_refin the validation checklist. -
“Multiple hold cycles” edge case not updated when Invariant 12 was extended (Pass 3). Refinement round 2 extended Invariant 12 to cover reinstate fields as a second overwrite exception, but the “Multiple hold cycles” edge case prose was not correspondingly updated — it still only mentioned hold fields being overwritten. A reader of the edge case who did not also check Invariant 12 would not know that
reinstated_byandreinstated_atfollow the same pattern on subsequent reinstate cycles. Resolved: edge case updated to explicitly state that eachreinstatecall overwritesreinstated_byandreinstated_at, parallel to the hold-field overwrite statement, consistent with the updated Invariant 12. -
Diversion investigation regulated adversarial scenario conflates Invariant 10 and Invariant 11 (Pass 3). The scenario stated “
discontinued_byanddiscontinuation_reasonmust be present (required by Invariant 11).” But Invariant 11 governs only reason fields —hold_reason,cancellation_reason,discontinuation_reason,amendment_reason. Actor reference fields, includingdiscontinued_by, are governed by Invariant 10. Citing Invariant 11 for an actor field is an incorrect attribution: an auditor who checks the cited invariant would not finddiscontinued_bymentioned there, undermining confidence in the regulated adversarial scenario’s correctness. Resolved: updated to “discontinued_by (Invariant 10) anddiscontinuation_reason(Invariant 11) must both be present and non-empty.”
Scheduled rescan: 2026-05-20. One refining finding; closed in-pattern.
readaction description and Decision point inconsistent on time-range filter support (Pass 1 / Pass 3). Thereadaction description listed supported filter axes as “order_id,patient_ref,medication_ref,prescriber_ref, state, or any combination” with no mention of time ranges. The Decision point, however, named “a time range with end before start isinvalid-query” — implying time-range filters are a supported axis. An implementor reading only the action description would not add time-range support; one reading only the Decision point would. The cross-section disagreement was a reference-graph violation (Pass 1) and an implementable ambiguity (Pass 3). Resolution:readaction description updated to add time ranges onordered_atas a supported filter axis, using the same{after, before}sub-key format Approval Step established.readDecision point updated to specify that anordered_attime range withafter>beforeisinvalid-query. This also aligns with the DEA audit use case (querying orders by date range), which Approval Step’s time-range-filteredreadsupports for its scope query but which Medication Order’sreadpreviously could not.