crd

package
v0.1.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package crd is a Da Vinci Coverage Requirements Discovery service (CRD 2.2.1): the payer's side of the CDS Hooks conversation that tells a clinician, while the order is still a draft, whether it is covered, whether it needs prior authorisation, and what documentation the payer will want.

CMS-0057's Prior Authorization API is in practice three Da Vinci guides together: CRD to say what is required, DTR to gather it, PAS to submit it. Perfuse had PAS. This is the first of the other two; DTR's $questionnaire-package is on the FHIR endpoint.

The coverage decisions come from a rules file, because they are the payer's policy and change without software releases: a code (or a list of codes) and what applies to it - covered or not, prior authorisation needed or not, documentation, and the DTR questionnaire that collects it. An order matching no rule is answered "conditional" and "indeterminate", which is what CRD says to return when the service cannot decide - never a guess that it is covered.

Responses follow the guide: a systemAction updating each order with the coverage-information extension, which the EHR stores on the order and later sends on with the prior authorisation; and a card per order, so a clinician sees it.

Index

Constants

View Source
const ExtCoverageInformation = "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-coverage-information"

ExtCoverageInformation is the CRD extension carrying a coverage decision on an order.

View Source
const Version = "2.2.1"

Version is the CRD guide this implements.

Variables

View Source
var ErrNoOrders = errors.New("the hook context carries no orders, appointments or encounter to answer about")

ErrNoOrders means the request named nothing to answer about.

View Source
var Hooks = []string{"order-sign", "order-select", "order-dispatch", "appointment-book", "encounter-start", "encounter-discharge"}

Hooks are the CDS Hooks this service answers: the six CRD 2.2.1 names (Supported Hooks, hook-4 asks a CRD server for a service for each). encounter-start and encounter-discharge were missing until the Da Vinci Burden Reduction provider reference implementation, pointed at this server, fired encounter-start and found no service for it.

Functions

This section is empty.

Types

type Action

type Action struct {
	Type        string         `json:"type"`
	Description string         `json:"description,omitempty"`
	Resource    map[string]any `json:"resource"`
	// contains filtered or unexported fields
}

Action is a systemAction: the EHR applies it without asking.

func (Action) MarshalJSON added in v0.1.6

func (a Action) MarshalJSON() ([]byte, error)

MarshalJSON writes the resource as the EHR sent it, plus the extension. Re-encoding from a map sorted every object's keys, and the Inferno CRD test kit, which compares arrays sorted by their JSON text, then read the reordered participants of an Appointment as a change outside the coverage-information.

type Advice added in v0.1.16

type Advice struct {
	Decides     bool       `json:"decides"`
	PolicyTitle string     `json:"policyTitle,omitempty"`
	Answer      string     `json:"answer,omitempty"` // approve, pend or deny
	Summary     string     `json:"summary,omitempty"`
	Missing     []string   `json:"missing,omitempty"`
	ToApprove   [][]string `json:"toApprove,omitempty"`
	// Questionnaire is the DTR questionnaire that asks for what is missing.
	Questionnaire string `json:"questionnaire,omitempty"`
}

Advice is a decision service's answer about an order before any request is made: what a prior authorization request would be told as the record stands. It is advice: the request that follows is decided on its own.

type Card

type Card struct {
	UUID      string         `json:"uuid"`
	Summary   string         `json:"summary"`
	Detail    string         `json:"detail,omitempty"`
	Indicator string         `json:"indicator"`
	Source    map[string]any `json:"source"`
	Links     []Link         `json:"links,omitempty"`
	Extension map[string]any `json:"extension,omitempty"`
}

Card is what a clinician sees.

type Code added in v0.1.6

type Code struct {
	System  string `yaml:"system" json:"system"`
	Code    string `yaml:"code" json:"code"`
	Display string `yaml:"display,omitempty" json:"display,omitempty"`
}

Code is a coding in a rules file.

type Contact added in v0.1.6

type Contact struct {
	Name  string `yaml:"name,omitempty" json:"name,omitempty"`
	Phone string `yaml:"phone,omitempty" json:"phone,omitempty"`
	Email string `yaml:"email,omitempty" json:"email,omitempty"`
	URL   string `yaml:"url,omitempty" json:"url,omitempty"`
}

Contact is a payer contact for an assertion.

type Detail added in v0.1.6

type Detail struct {
	// Code is from HL7's crd-coverage-detail code system: allowed-quantity, allowed-period, in-network-copay,
	// out-network-copay, concurrent-review, appropriate-use-needed, policy-link.
	Code string `yaml:"code" json:"code"`
	// Value is what the detail says, as text, or true/false.
	Value string `yaml:"value" json:"value"`
	// Qualification adds a condition on it.
	Qualification string `yaml:"qualification,omitempty" json:"qualification,omitempty"`
}

Detail is one of CRD's coverage details.

type Link struct {
	Label string `yaml:"label" json:"label"`
	URL   string `yaml:"url" json:"url"`
	Type  string `yaml:"type,omitempty" json:"type"`
}

Link is a card link.

type MemberCheck added in v0.1.6

type MemberCheck func(ctx context.Context, coverage, patient map[string]any, now time.Time) (Membership, string, error)

MemberCheck resolves the EHR's Coverage and Patient against the payer's member records, with a sentence saying why.

type Membership added in v0.1.6

type Membership string

Membership is what the payer's records say about the coverage an EHR sent: CRD's reasons for not-covered.

const (
	// MemberActive: the member and coverage were found and the coverage is in force.
	MemberActive Membership = ""
	// NoMemberFound: no member matches the patient (CRD reason no-member-found).
	NoMemberFound Membership = "no-member-found"
	// CoverageNotFound: the member is known but the coverage sent does not resolve to one of theirs (coverage-not-found).
	CoverageNotFound Membership = "coverage-not-found"
	// NoActiveCoverage: the coverage was found and is not in force now (no-active-coverage).
	NoActiveCoverage Membership = "no-active-coverage"
)

type PAAnswer added in v0.1.6

type PAAnswer struct {
	// Decision is "approve", "deny" or "pend".
	Decision string
	// Why is the rule's description, or empty when no rule names the service.
	Why string
	// AllowedQuantity is the rule's allowed-quantity detail, 0 when it has none: an approval asking for more is certified
	// for this many.
	AllowedQuantity float64
	// Questionnaire and Attachments say what a pended request must be supported with: the DTR questionnaire to fill in,
	// and the LOINC attachment codes of the documents to send.
	Questionnaire string
	Attachments   []string
	// AttachmentModifiers are LOINC attachment modifier codes for each attachment asked for.
	AttachmentModifiers []string
	// Alternative is the service approved instead, as a FHIR Coding; nil when there is none.
	Alternative map[string]any
}

PAAnswer is how a prior authorization request for one service is answered without a reviewer.

type Request

type Request struct {
	Hook         string `json:"hook"`
	HookInstance string `json:"hookInstance"`
	FHIRServer   string `json:"fhirServer,omitempty"`
	// FHIRAuthorization is the token for reading the EHR's FHIR server when prefetch does not carry what is needed.
	FHIRAuthorization *struct {
		AccessToken string `json:"access_token"`
	} `json:"fhirAuthorization,omitempty"`
	Context  map[string]json.RawMessage `json:"context"`
	Prefetch map[string]json.RawMessage `json:"prefetch,omitempty"`
	// Extension carries davinci-crd.configuration (the client's choice of options) and davinci-crd.requestedVersion.
	Extension map[string]json.RawMessage `json:"extension,omitempty"`

	// ClientVersion is the Da Vinci release the calling EHR's registration names, set by the server that authenticated it;
	// never read from the request body.
	ClientVersion string `json:"-"`
}

Request is a CDS Hooks service request.

type Response

type Response struct {
	Cards         []Card   `json:"cards"`
	SystemActions []Action `json:"systemActions,omitempty"`
}

Response is a CDS Hooks response.

type Rule

type Rule struct {
	// Codes are the procedure, device or service codes it applies to: CPT, HCPCS, SNOMED.
	Codes []string `yaml:"codes" json:"codes"`
	// System, when set, limits the match to codings in that system.
	System string `yaml:"system,omitempty" json:"system,omitempty"`
	// Description names the policy, for the card a clinician reads.
	Description string `yaml:"description" json:"description"`
	// Covered is covered, not-covered or conditional.
	Covered string `yaml:"covered" json:"covered"`
	// PA is no-auth, auth-needed, satisfied, performpa or conditional.
	PA string `yaml:"pa,omitempty" json:"pa,omitempty"`
	// Documentation is what must be gathered: clinical, admin, patient, conditional.
	Documentation []string `yaml:"documentation,omitempty" json:"documentation,omitempty"`
	// Questionnaire is the canonical URL of the DTR questionnaire that gathers it.
	Questionnaire string `yaml:"questionnaire,omitempty" json:"questionnaire,omitempty"`
	// Reason is shown to the clinician.
	Reason string `yaml:"reason,omitempty" json:"reason,omitempty"`
	// Links are policy documents.
	Links []Link `yaml:"links,omitempty" json:"links,omitempty"`

	// DocPurpose says what the documentation is for: withclaim, withorder, retain-doc or OTH, and withpa only when the rules
	// file sets allow_withpa: CRD 2.2.1's invariant crd-ci-q4 fails every coverage-information carrying withpa.
	DocPurpose []string `yaml:"doc_purpose,omitempty" json:"docPurpose,omitempty"`
	// BillingCodes are the codes to bill this under, when they differ from the order's.
	BillingCodes []Code `yaml:"billing_codes,omitempty" json:"billingCodes,omitempty"`
	// Details are CRD's name-value details: limits (allowed-quantity, allowed-period), costs (in-network-copay), and so on.
	Details []Detail `yaml:"details,omitempty" json:"details,omitempty"`
	// Contact is who to ask at the payer about this assertion.
	Contact *Contact `yaml:"contact,omitempty" json:"contact,omitempty"`
	// ExpiryDays is how long the assertion holds, from the day it is made.
	ExpiryDays int `yaml:"expiry_days,omitempty" json:"expiryDays,omitempty"`
	// DependsOn are codes of other orders this answer depends on: when one is in the same request, it is named as a
	// dependency, so the EHR knows to ask again if that order changes.
	DependsOn []string `yaml:"depends_on,omitempty" json:"dependsOn,omitempty"`

	// PADecision is what a Da Vinci PAS $submit for this service is answered without a reviewer: approve, deny or pend.
	// Empty derives it from the coverage answer: not-covered is denied, no-auth and satisfied are approved, and anything
	// else is pended for a person to decide. A service no rule names is always pended.
	PADecision string `yaml:"pa_decision,omitempty" json:"paDecision,omitempty"`
	// PAAttachments are the LOINC attachment codes (the valid-hl7-attachment-requests value set) of the documents a pended
	// PAS request for this service must be supported with. The response asks for them.
	PAAttachments []string `yaml:"pa_attachments,omitempty" json:"paAttachments,omitempty"`
	// PAAttachmentModifiers are LOINC attachment modifier codes that narrow what is asked for (a time window, say), sent
	// with each attachment request as written.
	PAAttachmentModifiers []string `yaml:"pa_attachment_modifiers,omitempty" json:"paAttachmentModifiers,omitempty"`
	// PAAlternative is a service the payer approves instead of this one (an X-ray before an MRI): the request is answered
	// modified, with the alternative as an added item.
	PAAlternative *Code `yaml:"pa_alternative,omitempty" json:"paAlternative,omitempty"`
	// contains filtered or unexported fields
}

Rule is one coverage policy.

type Rules

type Rules struct {
	// Payer names who is answering, on every card.
	Payer string `yaml:"payer" json:"payer"`
	// URL is the payer's site, on every card's source.
	URL   string `yaml:"url,omitempty" json:"url,omitempty"`
	Rules []Rule `yaml:"rules" json:"rules"`
	// Members says where the payer's own member records are, to resolve the coverage an EHR sends: "fhir" is this server's
	// FHIR store, the one $member-match reads. Empty: not checked, and only the Coverage's own status and period are read.
	Members string `yaml:"members,omitempty" json:"members,omitempty"`

	// DaVinciVersion is the CRD release (davinci.V21 or V22) answered when neither the request nor its client's registration
	// says; empty is the newest. Set by the server (-davinci-version), not by the rules file.
	DaVinciVersion string `yaml:"-" json:"-"`
	// AllowWithPA lets doc_purpose name withpa. CRD 2.2.1's invariant crd-ci-q4 is written so that every coverage-information
	// carrying withpa fails it, whatever pa-needed says; the guide's authors agree it is broken and a technical correction is
	// due. Until then the HL7 validator, and Inferno, reject such a response, so this is for a partner who checks against the
	// corrected guide. withpa is still refused beside a pa that says no authorization is needed, which is what crd-ci-q4 means.
	AllowWithPA bool `yaml:"allow_withpa,omitempty" json:"allowWithPA,omitempty"`

	// Check resolves the EHR's Coverage and Patient against the payer's records, when Members names them. Set by the server.
	Check MemberCheck `yaml:"-" json:"-"`
	// Authorized finds a prior authorization already approved for this patient and one of these codes, by its number, from
	// the payer's records. Set by the server with Members: fhir.
	Authorized func(ctx context.Context, coverage, patient map[string]any, codes []string, now time.Time) (string, error) `yaml:"-" json:"-"`
	// Client fetches what the EHR did not prefetch, from its fhirServer. Nil uses a client with a timeout.
	Client *http.Client `yaml:"-" json:"-"`
	// Advise, when set, asks a decision service what a prior authorization request for an order would be told as the
	// record stands (serve -crd-advisor-url): its answer is one more card. ok is false when the service gives no
	// advice, does not decide the service, or fails; the response is then exactly what it is without one.
	Advise func(ctx context.Context, system, code string, record []map[string]any) (advice *Advice, ok bool) `yaml:"-" json:"-"`
	// contains filtered or unexported fields
}

Rules is the rules file.

func LoadRules

func LoadRules(path string) (*Rules, error)

LoadRules reads and checks a rules file.

func (*Rules) Discovery

func (r *Rules) Discovery() map[string]any

Discovery is the CDS Hooks discovery document.

func (*Rules) Evaluate

func (r *Rules) Evaluate(req *Request, now time.Time) (*Response, error)

Evaluate answers a hook from what the request carries.

func (*Rules) EvaluateContext added in v0.1.6

func (r *Rules) EvaluateContext(ctx context.Context, req *Request, now time.Time) (*Response, error)

EvaluateContext answers a hook, fetching from the EHR's FHIR server what prefetch left out.

func (*Rules) PADecision added in v0.1.6

func (r *Rules) PADecision(codes ...map[string]any) PAAnswer

PADecision answers a prior authorization request for one service from the rules CRD answers with. codes are the service's codings, as FHIR CodeableConcepts (an item's productOrService, the requested order's code). A service no rule names is pended.

func (*Rules) QuestionnairesFor added in v0.1.6

func (r *Rules) QuestionnairesFor(assertionID string) []string

QuestionnairesFor returns the questionnaires a coverage assertion this service made asked for, for DTR's context parameter.

func (*Rules) Validate

func (r *Rules) Validate() error

Validate checks every rule uses CRD's codes, so a typo is refused at start rather than sent to an EHR.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL