Core concepts
The prescribing workflow
The lifecycle is modelled in full and implemented deliberately. Seventeen states and twenty-three transition actions exist as typed constants; two transitions are implemented, and every other action fails closed.
#Why the full lifecycle is modelled up front
Declaring the complete state and action vocabulary as typed constants — even where unimplemented — means the lifecycle can never be expressed with booleans or magic strings. It also means an unimplemented action has one predictable behaviour instead of an accidental one: it fails closed with an explicit capability error.
A single service is the sole transition authority. Infrastructure cannot invent a target state, version, reason, or timestamp; it may only execute a transition the domain has already authorized.
#Reachable today
| Transition | Effect | Status |
|---|---|---|
VALIDATE | In-memory DRAFT → READY_FOR_REVIEW at version 0, requiring a passing validation report bound to the same aggregate version and an unexpired draft. | Implemented locally |
EXPIRE | READY_FOR_REVIEW → EXPIRED at version 1, revoking every associated grant and session in the same transaction. | Implemented locally |
| The other 21 actions | APPROVE, SUBMIT, REQUEST_CANCELLATION, RECEIVE_REFILL_REQUEST and the rest are declared but unimplemented; each returns CAPABILITY_NOT_IMPLEMENTED. | Not implemented |
Two of the seventeen states are persistable. DRAFT exists only in memory, and the database independently rejects any state pair outside the two implemented ones — so even a privileged writer cannot record a state the application does not implement.
#The eight mechanical checks
Validation produces a versioned, persisted run with one capability code per check. Every run records clinicallyComplete=false, because mechanical validation is not clinical decision support.
- Exact medication identityThe medication resolves to exactly one deterministic synthetic identity, captured as an immutable snapshot with its source version.
- Active product statusObsolete or withdrawn fixtures are rejected rather than silently accepted.
- Non-controlled gateAny controlled or unknown-schedule result fails closed. Controlled-substance prescribing is disabled entirely.
- Prescription classificationThe request must resolve to the one supported classification,
STANDARD. - Quantity and versioned unitThe quantity must be positive, within bounds, and expressed in exactly one active unit code.
- Directions formatDirections must satisfy structural and length constraints supplied by configuration policy.
- Refill boundsRefill counts must fall inside the configured range for a non-controlled standard prescription.
- Explicit substitutionSubstitution preference must be stated explicitly rather than inferred from a default.
READY_FOR_REVIEW means eight mechanical checks passed. It does not mean the prescription is clinically appropriate. Drug-drug interaction, allergy, duplicate-therapy, dose-range, contraindication, and monitoring checks are Requires licensed content and are absent. The review surface states this explicitly rather than leaving it implied.
#Failure fixtures
The synthetic terminology source recognises a small NDC range so that failure paths are exercisable deterministically. Only 00000000000 resolves successfully; the others produce controlled failures — not found, ambiguous, obsolete, controlled, unknown schedule, source unavailable, over-the-counter, and malformed. Every one of them fails closed and persists no partial aggregate.
#Lifetimes
Expiration is enforced twice: a scheduled job sweeps due drafts in batches using row-level skip-locking, and every review access re-checks expiry synchronously. Reading a review never extends any lifetime.
#What the reviewer can do
Nothing but read. The review projection is validated against a strict schema that rejects unknown fields and any action-affordance field, and negative tests assert that no edit, approve, sign, submit, or transmit control renders. The absence of those controls is a tested property, not a styling decision.