davinci_crd_test_kit 0.14.1 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/presets/{inferno_crd_server_suite.json.erb → client_against_inferno_crd_server_suite.json.erb} +0 -33
- data/config/presets/{ri_crd_request_generator.json.erb → client_against_ri_crd_request_generator.json.erb} +1 -14
- data/config/presets/client_v221_against_inferno_crd_server_suite.json.erb +84 -0
- data/config/presets/client_v221_against_ri_br_provider.json.erb +31 -0
- data/config/presets/{ri_crd_request_generator.json_v221.json.erb → client_v221_against_ri_crd_request_generator.json.erb} +1 -1
- data/config/presets/{inferno_crd_client_suite.json.erb → server_against_inferno_crd_client_suite.json.erb} +0 -43
- data/config/presets/{ri_crd_server.json.erb → server_against_ri_crd_server.json.erb} +1 -44
- data/config/presets/{inferno_crd_client_suite_v221.json.erb → server_v221_against_inferno_crd_client_suite.json.erb} +0 -61
- data/config/presets/{inferno_crd_client_suite_prefetch_subset_v221.json.erb → server_v221_against_inferno_crd_client_suite_prefetch_subset.json.erb} +0 -46
- data/config/presets/server_v221_against_inferno_g31_suite.json.erb +49 -0
- data/lib/davinci_crd_test_kit/client/cross_hook_helper.rb +26 -0
- data/lib/davinci_crd_test_kit/client/endpoints/custom_service_response.rb +7 -7
- data/lib/davinci_crd_test_kit/client/endpoints/gather_response_generation_data.rb +4 -1
- data/lib/davinci_crd_test_kit/client/endpoints/hook_request_endpoint.rb +63 -38
- data/lib/davinci_crd_test_kit/client/endpoints/mock_service_response.rb +26 -7
- data/lib/davinci_crd_test_kit/client/endpoints/scenario_service_response.rb +54 -0
- data/lib/davinci_crd_test_kit/client/tagged_request_load_helper.rb +8 -27
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/retrieve_jwks_test.rb +35 -23
- data/lib/davinci_crd_test_kit/client/v2.0.1/auth/token_payload_test.rb +34 -21
- data/lib/davinci_crd_test_kit/client/v2.0.1/cds-services-v201.json +20 -20
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_appointment_book_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_discharge_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_encounter_start_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_hooks_group.rb +5 -5
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_dispatch_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_select_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/client_order_sign_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_coverage_information.rb +3 -36
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_external_reference.rb +3 -36
- data/lib/davinci_crd_test_kit/client/v2.0.1/must_support/client_card_must_support_instructions.rb +3 -36
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_fetched_data_test.rb +4 -13
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_request/hook_request_prefetch_equals_queried_test.rb +3 -13
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/client_display_cards_attest.rb +3 -13
- data/lib/davinci_crd_test_kit/client/v2.0.1/verify_response/inferno_response_validation.rb +3 -13
- data/lib/davinci_crd_test_kit/client/v2.2.1/api/client_coverage_info_update_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/attestation_instructions.rb +10 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_authorized_scope_attestation_test.rb +45 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_coverage_based_invocation_attestation_test.rb +44 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_data_element_expectations_attestation_test.rb +44 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_hook_invocation_logging_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_must_support_exposure_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_must_support_use_attestation_test.rb +41 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_order_sign_support_attestation_test.rb +42 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_prefetch_key_omission_attestation_test.rb +42 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_resource_identifiers_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_response_case_distinction_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_security_and_privacy_attestation_test.rb +43 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/attestations/client_workflow_integration_attestation_test.rb +44 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/decode_auth_token_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/retrieve_jwks_test.rb +29 -18
- data/lib/davinci_crd_test_kit/client/v2.2.1/auth/token_payload_test.rb +35 -22
- data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-prefetch-subset-v221.json +47 -47
- data/lib/davinci_crd_test_kit/client/v2.2.1/cds-services-v221.json +50 -50
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_appointment_book_group.rb +16 -14
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_attestations_group.rb +49 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_cross_hook_group.rb +22 -6
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_cross_hook_interaction_group.rb +98 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_discharge_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_encounter_start_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_fhir_api_group.rb +14 -12
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_hooks_group.rb +9 -9
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_long_running_hook_group.rb +2 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_dispatch_group.rb +16 -14
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_select_group.rb +12 -10
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_order_sign_group.rb +16 -14
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_scenarios_group.rb +26 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_self_pay_hook_group.rb +36 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/client_unknown_content_hook_group.rb +34 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/crd_client_suite.rb +19 -3
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_card_must_support_coverage_information_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_fhirpath_collection_as_comma_delimited_string_test.rb +4 -11
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_hook_instances_unique_test.rb +1 -9
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_location_address_propagation_test.rb +6 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/cross_hook/client_prefetch_complete_and_subset_test.rb +3 -12
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/appointment_book_receive_request_test.rb +8 -89
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/base_hook_invocation_receive_request_test.rb +163 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/cross_hooks_receive_request_test.rb +97 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_discharge_receive_request_test.rb +8 -90
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/encounter_start_receive_request_test.rb +8 -90
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_dispatch_receive_request_test.rb +8 -98
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_select_receive_request_test.rb +8 -98
- data/lib/davinci_crd_test_kit/client/v2.2.1/invocation/order_sign_receive_request_test.rb +8 -98
- data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_long_running_receive_request_test.rb +10 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/long_running/client_skip_long_running_attestation_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/self_pay/client_self_pay_no_request_test.rb +30 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/self_pay/client_self_pay_workflow_test.rb +55 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/unknown_content/client_unknown_content_attestation_test.rb +99 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/unknown_content/client_unknown_content_receive_request_test.rb +62 -0
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_conformance_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_coverage_verification_test.rb +10 -2
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_data_fetch_verification_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_granted_scopes_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_complete_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_prefetch_profiles_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_requested_version_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_request/hook_request_secured_transport_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/client_display_cards_attest.rb +52 -20
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/hook_response_support_coverage_information_test.rb +1 -1
- data/lib/davinci_crd_test_kit/client/v2.2.1/verify_response/inferno_response_validation.rb +6 -3
- data/lib/davinci_crd_test_kit/cross_suite/cards_identification.rb +9 -0
- data/lib/davinci_crd_test_kit/cross_suite/logical_models_override_helper.rb +30 -13
- data/lib/davinci_crd_test_kit/cross_suite/prefetch_profile_validation.rb +2 -0
- data/lib/davinci_crd_test_kit/cross_suite/requests_logical_model_validation.rb +26 -27
- data/lib/davinci_crd_test_kit/cross_suite/response_logical_model_validation.rb +48 -41
- data/lib/davinci_crd_test_kit/cross_suite/tags.rb +3 -0
- data/lib/davinci_crd_test_kit/requirements/cds-hooks_3.0.0-ballot_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/requirements/davinci_crd_test_kit_requirements.csv +6 -2
- data/lib/davinci_crd_test_kit/requirements/generated/crd_client_requirements_coverage.csv +107 -107
- data/lib/davinci_crd_test_kit/requirements/generated/crd_client_v221_requirements_coverage.csv +101 -97
- data/lib/davinci_crd_test_kit/requirements/generated/crd_server_requirements_coverage.csv +18 -18
- data/lib/davinci_crd_test_kit/requirements/generated/crd_server_v221_requirements_coverage.csv +36 -32
- data/lib/davinci_crd_test_kit/requirements/hl7.fhir.us.davinci-crd_2.2.1_requirements.xlsx +0 -0
- data/lib/davinci_crd_test_kit/server/v2.0.1/crd_server_suite.rb +1 -1
- data/lib/davinci_crd_test_kit/server/v2.0.1/server_hooks_group.rb +5 -5
- data/lib/davinci_crd_test_kit/server/v2.2.1/discovery/discovery_standard_prefetch_expressions_test.rb +1 -2
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_demonstrate_hook_response_group.rb +2 -2
- data/lib/davinci_crd_test_kit/server/v2.2.1/server_hooks_group.rb +5 -5
- data/lib/davinci_crd_test_kit/version.rb +2 -2
- metadata +40 -12
- data/config/presets/inferno_crd_server_suite_v221.json.erb +0 -94
|
@@ -13,15 +13,10 @@ module DaVinciCRDTestKit
|
|
|
13
13
|
'Practitioner', 'PractitionerRole'
|
|
14
14
|
].freeze
|
|
15
15
|
|
|
16
|
-
def validate_request_against_logical_model(request_body, request_index, ig_semver)
|
|
17
|
-
|
|
18
|
-
check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver)
|
|
19
|
-
else
|
|
20
|
-
conforms_to_logical_model?(request_body, "#{CRD_CDS_HOOK_REQUEST_MODEL_URL}|#{ig_semver}",
|
|
21
|
-
message_prefix: "(Request #{request_index + 1}) ")
|
|
22
|
-
end
|
|
16
|
+
def validate_request_against_logical_model(request_body, request_index, ig_semver, validator: :default)
|
|
17
|
+
check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver, validator:)
|
|
23
18
|
|
|
24
|
-
perform_version_specific_additional_verification(request_body, request_index, ig_semver)
|
|
19
|
+
perform_version_specific_additional_verification(request_body, request_index, ig_semver, validator:)
|
|
25
20
|
end
|
|
26
21
|
|
|
27
22
|
private
|
|
@@ -30,84 +25,88 @@ module DaVinciCRDTestKit
|
|
|
30
25
|
# Additional Validation to cover areas not checked or checked incorrectly by the logical models
|
|
31
26
|
# -------------------------------------------------------------------------
|
|
32
27
|
|
|
33
|
-
def perform_version_specific_additional_verification(request_body, request_index, ig_semver)
|
|
28
|
+
def perform_version_specific_additional_verification(request_body, request_index, ig_semver, validator: :default)
|
|
34
29
|
case ig_semver
|
|
35
30
|
when '2.2.1'
|
|
36
|
-
perform_v221_additional_verification(request_body, request_index)
|
|
31
|
+
perform_v221_additional_verification(request_body, request_index, validator:)
|
|
37
32
|
end
|
|
38
33
|
end
|
|
39
34
|
|
|
40
|
-
def perform_v221_additional_verification(request_body, request_index)
|
|
35
|
+
def perform_v221_additional_verification(request_body, request_index, validator: :default)
|
|
41
36
|
check_context_resources_for_ids(request_body, request_index)
|
|
42
37
|
check_relative_references(request_body, request_index)
|
|
43
|
-
check_context_resource_profiles(request_body, request_index, '2.2.1')
|
|
38
|
+
check_context_resource_profiles(request_body, request_index, '2.2.1', validator:)
|
|
44
39
|
end
|
|
45
40
|
|
|
46
41
|
# -------------------------------------------------------------------------
|
|
47
42
|
# Context resources profile check (not working in v2.2.1 logical models)
|
|
48
43
|
# -------------------------------------------------------------------------
|
|
49
44
|
|
|
50
|
-
def check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver)
|
|
45
|
+
def check_logical_model_conformance_no_resource_checks(request_body, request_index, ig_semver, validator: :default)
|
|
51
46
|
validation_issues = []
|
|
52
47
|
conforms_to_logical_model?(request_body, "#{CRD_CDS_HOOK_REQUEST_MODEL_URL}|#{ig_semver}",
|
|
53
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues
|
|
48
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues,
|
|
49
|
+
validator:)
|
|
54
50
|
|
|
55
|
-
reject_resource_issues(validation_issues)
|
|
51
|
+
filtered_issues = reject_resource_issues(validation_issues)
|
|
52
|
+
filter_logical_model_extension_issues(filtered_issues, validator)
|
|
53
|
+
filtered_issues.each do |issue|
|
|
56
54
|
next if issue.filtered
|
|
57
55
|
|
|
58
56
|
add_message(issue.severity, "(Request #{request_index + 1}) #{issue.message}")
|
|
59
57
|
end
|
|
60
58
|
end
|
|
61
59
|
|
|
62
|
-
def check_context_resource_profiles(request_body, request_index, ig_semver)
|
|
60
|
+
def check_context_resource_profiles(request_body, request_index, ig_semver, validator: :default)
|
|
63
61
|
case request_body['hook']
|
|
64
62
|
when 'order-sign', 'order-select'
|
|
65
|
-
draft_orders_conform_to_profiles?(request_body, request_index, ig_semver)
|
|
63
|
+
draft_orders_conform_to_profiles?(request_body, request_index, ig_semver, validator:)
|
|
66
64
|
when 'order-dispatch'
|
|
67
65
|
request_body.dig('context', 'fulfillmentTasks')&.each_with_index do |task, index|
|
|
68
66
|
resource = FHIR.from_contents(task.to_json)
|
|
69
67
|
resource_is_valid?(resource:, profile_url: "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-task-dispatch|#{ig_semver}",
|
|
70
|
-
message_prefix: "(Request #{request_index + 1}) " \
|
|
71
|
-
|
|
68
|
+
validator:, message_prefix: "(Request #{request_index + 1}) " \
|
|
69
|
+
"context.fulfillmentTasks entry #{index + 1} - ")
|
|
72
70
|
end
|
|
73
71
|
when 'appointment-book'
|
|
74
|
-
check_appointments_profiles(request_body, request_index, ig_semver)
|
|
72
|
+
check_appointments_profiles(request_body, request_index, ig_semver, validator:)
|
|
75
73
|
end
|
|
76
74
|
rescue JSON::ParserError
|
|
77
75
|
nil # no resource to validate - error found elsewhere
|
|
78
76
|
end
|
|
79
77
|
|
|
80
|
-
def draft_orders_conform_to_profiles?(request_body, request_index, ig_semver)
|
|
78
|
+
def draft_orders_conform_to_profiles?(request_body, request_index, ig_semver, validator: :default)
|
|
81
79
|
draft_orders = request_body.dig('context', 'draftOrders').to_json
|
|
82
80
|
resource = FHIR.from_contents(draft_orders)
|
|
83
81
|
resource_is_valid?(resource:, profile_url: "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-bundle-request|#{ig_semver}",
|
|
84
|
-
message_prefix: "(Request #{request_index + 1}) context.draftOrders - ")
|
|
82
|
+
message_prefix: "(Request #{request_index + 1}) context.draftOrders - ", validator:)
|
|
85
83
|
end
|
|
86
84
|
|
|
87
85
|
# -------------------------------------------------------------------------
|
|
88
86
|
# Appointment conformance (requires extra help to decide profile and check profile-based slicing)
|
|
89
87
|
# -------------------------------------------------------------------------
|
|
90
88
|
|
|
91
|
-
def check_appointments_profiles(request_body, request_index, ig_semver)
|
|
89
|
+
def check_appointments_profiles(request_body, request_index, ig_semver, validator: :default)
|
|
92
90
|
resource = FHIR.from_contents(request_body.dig('context', 'appointments')&.to_json)
|
|
93
91
|
return unless resource.is_a?(FHIR::Bundle)
|
|
94
92
|
|
|
95
93
|
check_bundle_non_entry_resource_conformance(resource,
|
|
96
94
|
"(Request #{request_index + 1}) context.appointments - ",
|
|
97
|
-
ig_semver
|
|
95
|
+
ig_semver,
|
|
96
|
+
validator:)
|
|
98
97
|
|
|
99
98
|
resource.entry.each_with_index do |entry, entry_index|
|
|
100
99
|
next unless entry.resource.present? # error caught on Bundle validation
|
|
101
100
|
|
|
102
101
|
error_prefix = "(Request #{request_index + 1}) context.appointments entry #{entry_index + 1} - "
|
|
103
|
-
check_appointment_conformance(entry.resource, request_body, error_prefix, ig_semver)
|
|
102
|
+
check_appointment_conformance(entry.resource, request_body, error_prefix, ig_semver, validator:)
|
|
104
103
|
end
|
|
105
104
|
end
|
|
106
105
|
|
|
107
|
-
def check_bundle_non_entry_resource_conformance(bundle, error_prefix, ig_semver)
|
|
106
|
+
def check_bundle_non_entry_resource_conformance(bundle, error_prefix, ig_semver, validator: :default)
|
|
108
107
|
validation_issues = []
|
|
109
108
|
resource_is_valid?(resource: bundle, profile_url: "http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-bundle-base|#{ig_semver}",
|
|
110
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues)
|
|
109
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues, validator:)
|
|
111
110
|
|
|
112
111
|
reject_entry_resource_issues(validation_issues).each do |issue|
|
|
113
112
|
add_message(issue.severity, "#{error_prefix}#{issue.message}")
|
|
@@ -39,21 +39,24 @@ module DaVinciCRDTestKit
|
|
|
39
39
|
"#{CRD_LOGICAL_MODEL_BASE}/#{profile_name}"
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def perform_response_logical_model_validation(cards, system_actions, request_body, response_index, ig_semver
|
|
42
|
+
def perform_response_logical_model_validation(cards, system_actions, request_body, response_index, ig_semver,
|
|
43
|
+
validator: :default)
|
|
43
44
|
if cards.is_a?(Array)
|
|
44
45
|
cards.each_with_index do |card, card_index|
|
|
45
|
-
validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver)
|
|
46
|
+
validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver, validator:)
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
return unless system_actions.is_a?(Array)
|
|
50
51
|
|
|
51
52
|
system_actions.each_with_index do |action, action_index|
|
|
52
|
-
validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver
|
|
53
|
+
validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver,
|
|
54
|
+
validator:)
|
|
53
55
|
end
|
|
54
56
|
end
|
|
55
57
|
|
|
56
|
-
def validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver
|
|
58
|
+
def validate_card_against_logical_model(card, response_index, request_body, card_index, ig_semver,
|
|
59
|
+
validator: :default)
|
|
57
60
|
label = logical_model_entity_label(response_index, card_index, 'card')
|
|
58
61
|
unless card.is_a?(Hash)
|
|
59
62
|
add_message('error', "#{label} is not a JSON object; skipping logical model validation.")
|
|
@@ -71,7 +74,8 @@ module DaVinciCRDTestKit
|
|
|
71
74
|
|
|
72
75
|
validation_issues = []
|
|
73
76
|
conforms_to_logical_model?({ 'cards' => [card] }, logical_model_url(profile_name),
|
|
74
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues
|
|
77
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues,
|
|
78
|
+
validator:)
|
|
75
79
|
|
|
76
80
|
validate_summary_length(card, label)
|
|
77
81
|
validate_suggestion_uuid_presence(card, label) unless ['v201', '2.0.1'].include? ig_semver
|
|
@@ -79,7 +83,8 @@ module DaVinciCRDTestKit
|
|
|
79
83
|
|
|
80
84
|
error_prefix = "#{label} (#{card_type || 'uncategorized'}): "
|
|
81
85
|
filtered_issues = manually_check_card_specific_errors(card, validation_issues, card_type,
|
|
82
|
-
request_body, error_prefix, ig_semver)
|
|
86
|
+
request_body, error_prefix, ig_semver, validator:)
|
|
87
|
+
filter_logical_model_extension_issues(filtered_issues, validator)
|
|
83
88
|
add_messages_not_excluded(filtered_issues, error_prefix)
|
|
84
89
|
end
|
|
85
90
|
|
|
@@ -123,7 +128,8 @@ module DaVinciCRDTestKit
|
|
|
123
128
|
)
|
|
124
129
|
end
|
|
125
130
|
|
|
126
|
-
def validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver
|
|
131
|
+
def validate_system_action_against_logical_model(action, response_index, request_body, action_index, ig_semver,
|
|
132
|
+
validator: :default)
|
|
127
133
|
label = logical_model_entity_label(response_index, action_index, 'systemAction')
|
|
128
134
|
unless action.is_a?(Hash)
|
|
129
135
|
add_message('error', "#{label} is not a JSON object; skipping logical model validation.")
|
|
@@ -146,11 +152,12 @@ module DaVinciCRDTestKit
|
|
|
146
152
|
|
|
147
153
|
validation_issues = []
|
|
148
154
|
conforms_to_logical_model?({ 'systemActions' => [action] }, logical_model_url(profile_name),
|
|
149
|
-
add_messages_to_runnable: false, validator_response_details: validation_issues
|
|
155
|
+
add_messages_to_runnable: false, validator_response_details: validation_issues,
|
|
156
|
+
validator:)
|
|
150
157
|
|
|
151
158
|
validation_issues
|
|
152
159
|
.reject! do |issue|
|
|
153
|
-
issue.message.match?(%r{The extension definition http://hl7\.org/fhir/us/davinci-crd/StructureDefinition/CDSHookServiceResponseExtensionIfNoneExist
|
|
160
|
+
issue.message.match?(%r{CDSHooksResponse\.systemActions\[\d+\]\.extension: The extension definition http://hl7\.org/fhir/us/davinci-crd/StructureDefinition/CDSHookServiceResponseExtensionIfNoneExist\|2\.2\.1 defines the contexts of use as}) # rubocop:disable Layout/LineLength
|
|
154
161
|
end
|
|
155
162
|
|
|
156
163
|
if action_type == CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE
|
|
@@ -158,7 +165,8 @@ module DaVinciCRDTestKit
|
|
|
158
165
|
end
|
|
159
166
|
error_prefix = "#{label} (#{action_type || 'uncategorized'}): "
|
|
160
167
|
filtered_issues = manually_check_action_specific_errors(action, validation_issues, action_type,
|
|
161
|
-
request_body, error_prefix, ig_semver)
|
|
168
|
+
request_body, error_prefix, ig_semver, validator:)
|
|
169
|
+
filter_logical_model_extension_issues(filtered_issues, validator)
|
|
162
170
|
add_messages_not_excluded(filtered_issues, error_prefix)
|
|
163
171
|
end
|
|
164
172
|
|
|
@@ -253,7 +261,7 @@ module DaVinciCRDTestKit
|
|
|
253
261
|
|
|
254
262
|
def add_messages_not_excluded(issues, error_prefix)
|
|
255
263
|
issues.each do |issue|
|
|
256
|
-
next if issue.filtered
|
|
264
|
+
next if issue.filtered
|
|
257
265
|
|
|
258
266
|
add_message(issue.severity, "#{error_prefix}#{issue.message}")
|
|
259
267
|
end
|
|
@@ -267,21 +275,17 @@ module DaVinciCRDTestKit
|
|
|
267
275
|
# Validator Filtering and Manual Checks Depending on the Card Type
|
|
268
276
|
# -------------------------------------------------------------------------
|
|
269
277
|
|
|
270
|
-
def logical_model_extension_issue?(issue)
|
|
271
|
-
issue.message.match(/\.extension: Unrecognized property/).present?
|
|
272
|
-
end
|
|
273
|
-
|
|
274
278
|
def manually_check_card_specific_errors(card, validation_issues, card_type, request_body, error_prefix,
|
|
275
|
-
ig_semver)
|
|
279
|
+
ig_semver, validator: :default)
|
|
276
280
|
case card_type
|
|
277
281
|
when CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE
|
|
278
|
-
manually_check_form_completion_errors(card, validation_issues, error_prefix)
|
|
282
|
+
manually_check_form_completion_errors(card, validation_issues, error_prefix, validator:)
|
|
279
283
|
when CardsIdentification::PROPOSE_ALTERNATIVE_REQUEST_RESPONSE_TYPE
|
|
280
284
|
manually_check_propose_alternative_errors(card, validation_issues, request_body,
|
|
281
|
-
error_prefix, ig_semver)
|
|
285
|
+
error_prefix, ig_semver, validator:)
|
|
282
286
|
when CardsIdentification::ADDITIONAL_ORDERS_RESPONSE_TYPE
|
|
283
287
|
manually_check_additional_orders_errors(card, validation_issues, request_body,
|
|
284
|
-
error_prefix, ig_semver)
|
|
288
|
+
error_prefix, ig_semver, validator:)
|
|
285
289
|
when CardsIdentification::LAUNCH_SMART_APP_RESPONSE_TYPE
|
|
286
290
|
manually_check_launch_smart_app_errors(validation_issues)
|
|
287
291
|
else
|
|
@@ -290,26 +294,26 @@ module DaVinciCRDTestKit
|
|
|
290
294
|
end
|
|
291
295
|
|
|
292
296
|
def manually_check_action_specific_errors(action, validation_issues, action_type, request_body,
|
|
293
|
-
error_prefix, ig_semver)
|
|
297
|
+
error_prefix, ig_semver, validator: :default)
|
|
294
298
|
case action_type
|
|
295
299
|
when DaVinciCRDTestKit::CardsIdentification::COVERAGE_INFORMATION_RESPONSE_TYPE
|
|
296
300
|
manually_check_coverage_information_errors(action, validation_issues, request_body,
|
|
297
|
-
error_prefix, ig_semver)
|
|
301
|
+
error_prefix, ig_semver, validator:)
|
|
298
302
|
when DaVinciCRDTestKit::CardsIdentification::CREATE_OR_UPDATE_COVERAGE_RESPONSE_TYPE
|
|
299
303
|
manually_check_update_coverage_action_errors(action, validation_issues,
|
|
300
|
-
error_prefix, ig_semver)
|
|
304
|
+
error_prefix, ig_semver, validator:)
|
|
301
305
|
when DaVinciCRDTestKit::CardsIdentification::FORM_COMPLETION_RESPONSE_TYPE
|
|
302
306
|
manually_check_form_completion_action_errors(action, validation_issues,
|
|
303
|
-
error_prefix, ig_semver)
|
|
307
|
+
error_prefix, ig_semver, validator:)
|
|
304
308
|
else
|
|
305
309
|
validation_issues
|
|
306
310
|
end
|
|
307
311
|
end
|
|
308
312
|
|
|
309
|
-
def manually_check_form_completion_errors(card, validation_issues, error_prefix)
|
|
313
|
+
def manually_check_form_completion_errors(card, validation_issues, error_prefix, validator: :default)
|
|
310
314
|
validation_issues.reject do |issue|
|
|
311
315
|
if issue.message.match?(/The type 'Questionnaire' is not valid - must be Task/)
|
|
312
|
-
check_questionnaire_actions(card, issue.message, error_prefix)
|
|
316
|
+
check_questionnaire_actions(card, issue.message, error_prefix, validator:)
|
|
313
317
|
true
|
|
314
318
|
else
|
|
315
319
|
false
|
|
@@ -317,7 +321,7 @@ module DaVinciCRDTestKit
|
|
|
317
321
|
end
|
|
318
322
|
end
|
|
319
323
|
|
|
320
|
-
def check_questionnaire_actions(card, error_message, error_prefix)
|
|
324
|
+
def check_questionnaire_actions(card, error_message, error_prefix, validator: :default)
|
|
321
325
|
extracted_indexes =
|
|
322
326
|
error_message.match(/CDSHooksResponse\.cards\[0\]\.suggestions\[(\d+)\]\.actions\[(\d+)\]\.resource/)
|
|
323
327
|
unless extracted_indexes
|
|
@@ -330,7 +334,7 @@ module DaVinciCRDTestKit
|
|
|
330
334
|
|
|
331
335
|
message_prefix = "#{error_prefix} suggestion #{suggestion_index + 1}, action #{action_index + 1} - "
|
|
332
336
|
resource = FHIR.from_contents(card['suggestions'][suggestion_index]['actions'][action_index]['resource'].to_json)
|
|
333
|
-
resource_is_valid?(resource:, message_prefix:) # no questionnaire profile applied per CRD
|
|
337
|
+
resource_is_valid?(resource:, message_prefix:, validator:) # no questionnaire profile applied per CRD
|
|
334
338
|
|
|
335
339
|
return if resource.id.present?
|
|
336
340
|
|
|
@@ -344,12 +348,13 @@ module DaVinciCRDTestKit
|
|
|
344
348
|
end
|
|
345
349
|
|
|
346
350
|
def manually_check_propose_alternative_errors(card, validation_issues, request_body,
|
|
347
|
-
error_prefix, ig_semver)
|
|
351
|
+
error_prefix, ig_semver, validator: :default)
|
|
348
352
|
no_resource_issues = manually_check_action_resources_for_order_profile_conformance(card,
|
|
349
353
|
validation_issues,
|
|
350
354
|
request_body,
|
|
351
355
|
error_prefix,
|
|
352
|
-
ig_semver
|
|
356
|
+
ig_semver,
|
|
357
|
+
validator:)
|
|
353
358
|
|
|
354
359
|
no_resource_issues.each do |issue|
|
|
355
360
|
next unless issue.message.match?(/Constraint failed: crd-respar-1/)
|
|
@@ -368,23 +373,24 @@ module DaVinciCRDTestKit
|
|
|
368
373
|
end
|
|
369
374
|
|
|
370
375
|
def manually_check_additional_orders_errors(card, validation_issues, request_body,
|
|
371
|
-
error_prefix, ig_semver)
|
|
376
|
+
error_prefix, ig_semver, validator: :default)
|
|
372
377
|
manually_check_action_resources_for_order_profile_conformance(card,
|
|
373
378
|
validation_issues,
|
|
374
379
|
request_body,
|
|
375
380
|
error_prefix,
|
|
376
|
-
ig_semver
|
|
381
|
+
ig_semver,
|
|
382
|
+
validator:)
|
|
377
383
|
end
|
|
378
384
|
|
|
379
385
|
def manually_check_action_resources_for_order_profile_conformance(card, validation_issues, request_body,
|
|
380
|
-
error_prefix, ig_semver)
|
|
386
|
+
error_prefix, ig_semver, validator: :default)
|
|
381
387
|
if card['suggestions'].present?
|
|
382
388
|
card['suggestions'].each_with_index do |suggestion, suggestion_index|
|
|
383
389
|
next unless suggestion['actions'].present?
|
|
384
390
|
|
|
385
391
|
suggestion['actions'].each_with_index do |action, action_index|
|
|
386
392
|
action_error_prefix = "#{error_prefix}suggestion #{suggestion_index + 1}, action #{action_index + 1} - "
|
|
387
|
-
check_action_target(action, request_body, action_error_prefix, ig_semver)
|
|
393
|
+
check_action_target(action, request_body, action_error_prefix, ig_semver, validator:)
|
|
388
394
|
end
|
|
389
395
|
end
|
|
390
396
|
end
|
|
@@ -392,36 +398,37 @@ module DaVinciCRDTestKit
|
|
|
392
398
|
reject_resource_issues(validation_issues)
|
|
393
399
|
end
|
|
394
400
|
|
|
395
|
-
def check_action_target(action, request_body, error_prefix, ig_semver)
|
|
401
|
+
def check_action_target(action, request_body, error_prefix, ig_semver, validator: :default)
|
|
396
402
|
local_reference?(action['resourceId'], error_prefix) if action['resourceId'].present?
|
|
397
403
|
return unless action['resource'].present?
|
|
398
404
|
|
|
399
|
-
check_resource_conformance_to_order_profile(action['resource'], request_body, error_prefix, ig_semver)
|
|
405
|
+
check_resource_conformance_to_order_profile(action['resource'], request_body, error_prefix, ig_semver, validator:)
|
|
400
406
|
end
|
|
401
407
|
|
|
402
408
|
def manually_check_coverage_information_errors(action, validation_issues, request_body,
|
|
403
|
-
error_prefix, ig_semver)
|
|
409
|
+
error_prefix, ig_semver, validator: :default)
|
|
404
410
|
if action['resource'].present?
|
|
405
411
|
check_resource_conformance_to_order_or_encounter_profile(action['resource'], request_body,
|
|
406
|
-
error_prefix, ig_semver)
|
|
412
|
+
error_prefix, ig_semver, validator:)
|
|
407
413
|
end
|
|
408
414
|
reject_resource_issues(validation_issues)
|
|
409
415
|
end
|
|
410
416
|
|
|
411
417
|
def manually_check_update_coverage_action_errors(action, validation_issues,
|
|
412
|
-
error_prefix, ig_semver)
|
|
418
|
+
error_prefix, ig_semver, validator: :default)
|
|
413
419
|
check_required_action_type(action, 'update', error_prefix, 'coverage update action response type')
|
|
414
420
|
if action['resource'].present?
|
|
415
|
-
check_resource_conformance_to_coverage_profile(action['resource'], error_prefix, ig_semver)
|
|
421
|
+
check_resource_conformance_to_coverage_profile(action['resource'], error_prefix, ig_semver, validator:)
|
|
416
422
|
end
|
|
417
423
|
reject_resource_issues(validation_issues)
|
|
418
424
|
end
|
|
419
425
|
|
|
420
426
|
def manually_check_form_completion_action_errors(action, validation_issues,
|
|
421
|
-
error_prefix, ig_semver)
|
|
427
|
+
error_prefix, ig_semver, validator: :default)
|
|
422
428
|
check_required_action_type(action, 'create', error_prefix, 'form completion action response type')
|
|
423
429
|
if action['resource'].present?
|
|
424
|
-
check_resource_conformance_to_questionnaire_task_profile(action['resource'], error_prefix, ig_semver
|
|
430
|
+
check_resource_conformance_to_questionnaire_task_profile(action['resource'], error_prefix, ig_semver,
|
|
431
|
+
validator:)
|
|
425
432
|
end
|
|
426
433
|
reject_resource_issues(validation_issues)
|
|
427
434
|
end
|
|
@@ -7,12 +7,15 @@ module DaVinciCRDTestKit
|
|
|
7
7
|
ORDER_SIGN_TAG = 'order-sign'.freeze
|
|
8
8
|
DISCOVERY_TAG = 'cds_discovery'.freeze
|
|
9
9
|
ANY_HOOK_TAG = 'any_hook'.freeze
|
|
10
|
+
CROSS_HOOK_ANALYSIS_TAG = 'cross_hook'.freeze
|
|
10
11
|
DATA_FETCH_TAG = 'data_fetch'.freeze
|
|
11
12
|
PAYER_ORG_FETCH_TAG = 'payer_org'.freeze
|
|
12
13
|
PARENT_LOCATION_FETCH_TAG = 'parent_location'.freeze
|
|
13
14
|
HOOK_INSTANCE_TAG_PREFIX = 'hi_'.freeze
|
|
14
15
|
HOOK_INSTANCE_DATA_FETCH_TAG_PREFIX = 'hi_data_fetch_'.freeze
|
|
15
16
|
LONG_RUNNING_GROUP_TAG = 'long_running_request'.freeze
|
|
17
|
+
UNKNOWN_CONTENT_GROUP_TAG = 'unknown_content_request'.freeze
|
|
18
|
+
SELF_PAY_GROUP_TAG = 'self_pay_request'.freeze
|
|
16
19
|
DUPLICATED_HOOK_INSTANCE_TAG = 'duplicate_hook_instance'.freeze
|
|
17
20
|
COVERAGE_INFO_DISABLED_TAG = 'coverage-info-disabled'.freeze
|
|
18
21
|
TECHNICAL_ISSUES_TAG = 'technical-issues'.freeze
|
|
Binary file
|
|
@@ -1216,7 +1216,7 @@ hl7.fhir.us.davinci-crd_2.2.1,hook-35,https://hl7.org/fhir/us/davinci-crd/2.2.1/
|
|
|
1216
1216
|
hl7.fhir.us.davinci-crd_2.2.1,hook-36,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/hooks.html#ci-c-hook-36,"Where CRD Clients have an appropriate workflow and data capture mechanism, the order-select hook **MAY** be used in scenarios that do not involve creating a true order.",MAY,CRD Client,,true,,
|
|
1217
1217
|
hl7.fhir.us.davinci-crd_2.2.1,hook-37,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/hooks.html#ci-c-hook-37,The 'context' field in invocations of the order-sign hook **SHALL** conform to the logical model specified [here](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-CRDOrderSignContext.html),SHALL,CRD Client,,true,,
|
|
1218
1218
|
hl7.fhir.us.davinci-crd_2.2.1,hook-38,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/hooks.html#ci-c-hook-38,CRD Servers **MAY** use the order-sign hook as a basis for associating a patient with a particular practitioner from a payer attribution perspective.,MAY,CRD Server,,false,,
|
|
1219
|
-
hl7.fhir.us.davinci-crd_2.2.1,hook-39,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/hooks.html#ci-c-hook-39,"CRD clients and servers **SHALL**, at minimum, support returning and processing the [Coverage Information](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html) system action for all invocations of the order-
|
|
1219
|
+
hl7.fhir.us.davinci-crd_2.2.1,hook-39,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/hooks.html#ci-c-hook-39,"CRD clients and servers **SHALL**, at minimum, support returning and processing the [Coverage Information](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-ext-coverage-information.html) system action for all invocations of the order-sign hook.",SHALL,"CRD Client, CRD Server",,false,,
|
|
1220
1220
|
hl7.fhir.us.davinci-crd_2.2.1,impl-1,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/implementation.html#ci-c-impl-1,Clients that suppress 'default presumption' coverage-information of messages **SHALL** mitigate the potential for misinterpretation in the event CRD is unavailable.,SHALL,CRD Client,,false,,
|
|
1221
1221
|
hl7.fhir.us.davinci-crd_2.2.1,impl-2,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/implementation.html#ci-c-impl-2,CRD servers **SHOULD** strive to achieve a minimum of 3-9s availability for their services and strive to provide at least some level of useful response to CRD clients even if some of their back-end systems are unavailable.,SHOULD,CRD Server,,false,,
|
|
1222
1222
|
hl7.fhir.us.davinci-crd_2.2.1,impl-3,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/implementation.html#ci-c-impl-3,"Even if implemented using multiple components, there is still a requirement that the exchanges between the provider HIT (including any ePA coordinators) and the payer HIT (including any ePA coordinators) **SHALL** replicate all of the defined exchanges between provider and payer.",SHALL,"CRD Client, CRD Server",,false,,
|
|
@@ -1311,7 +1311,11 @@ hl7.fhir.us.davinci-crd_2.2.1,resp-69,https://hl7.org/fhir/us/davinci-crd/2.2.1/
|
|
|
1311
1311
|
hl7.fhir.us.davinci-crd_2.2.1,resp-70,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#ci-c-resp-70,"If returning a card rather than a system action, the ""Update Coverage Records"" response type **SHOULD NOT** be returned for hook types that are likely to be triggered by clinical users rather than administrative staff. Cards of this type would be appropriate for hooks such as encounter-start or appointment-book but would not be appropriate for order-select or order-sign.",SHOULD NOT,CRD Server,,true,,
|
|
1312
1312
|
hl7.fhir.us.davinci-crd_2.2.1,resp-71,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#ci-c-resp-71,Adjust Coverage responses **SHALL** comply with the logical model profile found [here](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-CRDHooksResponse-adjustCoverage.html).,SHALL,CRD Server,,false,,
|
|
1313
1313
|
hl7.fhir.us.davinci-crd_2.2.1,resp-72,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/cards.html#ci-c-resp-72,Launch SMART responses **SHALL** comply with the logical model profile found [here](https://hl7.org/fhir/us/davinci-crd/2.2.1/en/StructureDefinition-CRDHooksResponse-launchSMART.html).,SHALL,CRD Server,,false,,
|
|
1314
|
-
hl7.fhir.us.davinci-crd_2.2.1,sec-1,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/security.html#ci-c-sec-1,Implementers SHALL adhere to
|
|
1314
|
+
hl7.fhir.us.davinci-crd_2.2.1,sec-1,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/security.html#ci-c-sec-1,"Implementers SHALL adhere to any security and privacy rules defined by:
|
|
1315
|
+
- FHIR Core: [Security & Privacy Module](http://hl7.org/fhir/R4/secpriv-module.html), [Security Principles](http://hl7.org/fhir/R4/security.html) and [Implementer's Checklist](http://hl7.org/fhir/R4/safety.html)
|
|
1316
|
+
- HRex: [Privacy & Security](http://hl7.org/fhir/us/davinci-hrex/1.2.0/security.html)
|
|
1317
|
+
- CDS Hooks: [Security & Safety](http://cds-hooks.hl7.org/2026Jan/index.html#security-and-safety)
|
|
1318
|
+
- SMART on FHIR: [SMART App Launch](http://www.hl7.org/fhir/smart-app-launch)",SHALL,"CRD Client, CRD Server",,false,,
|
|
1315
1319
|
hl7.fhir.us.davinci-crd_2.2.1,sec-2,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/security.html#ci-c-sec-2,"As per the CDS Hooks specification, communications between CRD clients and CRD servers **SHALL** use TLS.",SHALL,"CRD Client, CRD Server",,false,,
|
|
1316
1320
|
hl7.fhir.us.davinci-crd_2.2.1,sec-3,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/security.html#ci-c-sec-3,CRD servers and CRD clients **SHOULD** enforce a minimum version and other TLS configuration requirements based on [HRex rules](http://hl7.org/fhir/us/davinci-hrex/1.2.0/security.html#exchange-security) for PHI exchange.,SHOULD,"CRD Client, CRD Server",,false,,
|
|
1317
1321
|
hl7.fhir.us.davinci-crd_2.2.1,sec-4,https://hl7.org/fhir/us/davinci-crd/2.2.1/en/security.html#ci-c-sec-4,CRD clients that support the Launch SMART Application Response Type **SHALL** support running applications that adhere to the SMART on FHIR [confidential app](https://hl7.org/fhir/smart-app-launch/STU2.2/app-launch.html#support-for-public-and-confidential-apps) profile.,SHALL,CRD Client,,true,,
|