@nexalink/coding-contracts 0.1.0 → 0.3.0
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.
- package/LICENSE +23 -0
- package/README.md +200 -0
- package/dist/cjs/index.cjs +4305 -69
- package/dist/index.d.ts +1037 -2
- package/dist/index.js +4279 -68
- package/package.json +24 -5
- package/schemas/coding-batch.schema.json +63 -0
- package/schemas/coding-case-clinical.schema.json +428 -0
- package/schemas/coding-case-context.schema.json +128 -0
- package/schemas/coding-case-payer.schema.json +126 -0
- package/schemas/coding-case.schema.json +97 -0
- package/schemas/coding-decision-line.schema.json +172 -0
- package/schemas/coding-decision.schema.json +430 -0
- package/schemas/coding-evidence.schema.json +100 -0
- package/schemas/coding-extension.schema.json +36 -0
- package/schemas/coding-reviewer-action.schema.json +53 -0
- package/schemas/coding-rule-result.schema.json +90 -0
- package/schemas/coding-service-line.schema.json +120 -0
- package/versions.json +62 -2
- package/workflow-constants.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,15 +1,59 @@
|
|
|
1
1
|
// GENERATED FILE. DO NOT EDIT.
|
|
2
|
-
// Source:
|
|
2
|
+
// Source: coding-contracts schemas/ (run: bun run contracts:gen)
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
5
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
-
|
|
6
|
+
const ISO_DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
7
|
+
const isIsoDate = (value) => {
|
|
8
|
+
const match = ISO_DATE_PATTERN.exec(value);
|
|
9
|
+
if (!match)
|
|
10
|
+
return false;
|
|
11
|
+
const year = Number(match[1]);
|
|
12
|
+
const month = Number(match[2]);
|
|
13
|
+
const day = Number(match[3]);
|
|
14
|
+
if (year < 1 || month < 1 || month > 12)
|
|
15
|
+
return false;
|
|
16
|
+
const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
17
|
+
const daysInMonth = [
|
|
18
|
+
31,
|
|
19
|
+
leapYear ? 29 : 28,
|
|
20
|
+
31,
|
|
21
|
+
30,
|
|
22
|
+
31,
|
|
23
|
+
30,
|
|
24
|
+
31,
|
|
25
|
+
31,
|
|
26
|
+
30,
|
|
27
|
+
31,
|
|
28
|
+
30,
|
|
29
|
+
31,
|
|
30
|
+
];
|
|
31
|
+
return day >= 1 && day <= daysInMonth[month - 1];
|
|
32
|
+
};
|
|
33
|
+
const RFC3339_DATETIME_PATTERN = /^(\d{4}-\d{2}-\d{2})T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
|
|
34
|
+
const isRfc3339DateTime = (value) => {
|
|
35
|
+
const match = RFC3339_DATETIME_PATTERN.exec(value);
|
|
36
|
+
return match !== null && isIsoDate(match[1]);
|
|
37
|
+
};
|
|
38
|
+
// Canonical workflow constants (source: workflow-constants.json).
|
|
7
39
|
export const RCM_WORKFLOW_ID = "rcm-coding-assistance";
|
|
8
40
|
export const RCM_MODEL_POLICY_ID = "carecompass-rcm-review-v1";
|
|
9
41
|
export const RCM_HUMAN_REVIEW_POLICY_ID = "qualified-coder-review-v1";
|
|
10
42
|
export const RCM_OUTPUT_SCHEMA_NAME = "carecompass_rcm_grounded_review";
|
|
11
43
|
export const RCM_HUMAN_REVIEW_INSTRUCTION = "Qualified human coder review is required before billing, coding, or claim submission.";
|
|
12
|
-
// Schema wire versions (source:
|
|
44
|
+
// Schema wire versions (source: schemas/*.schema.json).
|
|
45
|
+
export const CODING_CASE_CONTEXT_SCHEMA_VERSION = "coding-case-context-v1";
|
|
46
|
+
export const CODING_CASE_PAYER_SCHEMA_VERSION = "coding-case-payer-v1";
|
|
47
|
+
export const CODING_CASE_CLINICAL_SCHEMA_VERSION = "coding-case-clinical-v1";
|
|
48
|
+
export const CODING_SERVICE_LINE_SCHEMA_VERSION = "coding-service-line-v1";
|
|
49
|
+
export const CODING_EXTENSION_SCHEMA_VERSION = "coding-extension-v1";
|
|
50
|
+
export const CODING_CASE_SCHEMA_VERSION = "coding-case-v1";
|
|
51
|
+
export const CODING_BATCH_SCHEMA_VERSION = "coding-batch-v1";
|
|
52
|
+
export const CODING_DECISION_LINE_SCHEMA_VERSION = "coding-decision-line-v1";
|
|
53
|
+
export const CODING_EVIDENCE_SCHEMA_VERSION = "coding-evidence-v1";
|
|
54
|
+
export const CODING_RULE_RESULT_SCHEMA_VERSION = "coding-rule-result-v1";
|
|
55
|
+
export const CODING_REVIEWER_ACTION_SCHEMA_VERSION = "coding-reviewer-action-v1";
|
|
56
|
+
export const CODING_DECISION_SCHEMA_VERSION = "coding-decision-v1";
|
|
13
57
|
export const RCM_REFERENCE_SCHEMA_VERSION = "rcm-supporting-reference-v1";
|
|
14
58
|
export const RCM_INPUT_SCHEMA_VERSION = "rcm-coding-input-v1";
|
|
15
59
|
export const RCM_OUTPUT_SCHEMA_VERSION = "rcm-grounded-human-review-v2";
|
|
@@ -18,6 +62,4159 @@ export const RCM_RETRIEVAL_SCHEMA_VERSION = "rcm-retrieval-metadata-v1";
|
|
|
18
62
|
export const RCM_RUNTIME_EVENT_SCHEMA_VERSION = "rcm-runtime-event-v1";
|
|
19
63
|
export const RCM_WORKFLOW_CATALOG_SCHEMA_VERSION = "rcm-workflow-catalog-v1";
|
|
20
64
|
// --------------------------------------------------------------------
|
|
65
|
+
// CodingCaseContext (schema 1.0.0, wire coding-case-context-v1)
|
|
66
|
+
// --------------------------------------------------------------------
|
|
67
|
+
export const codingCaseContextSchema = z
|
|
68
|
+
.object({
|
|
69
|
+
setting: z.enum([
|
|
70
|
+
"professional",
|
|
71
|
+
"facility",
|
|
72
|
+
"pharmacy",
|
|
73
|
+
"dental",
|
|
74
|
+
"risk_adjustment",
|
|
75
|
+
"other",
|
|
76
|
+
]),
|
|
77
|
+
otherSettingDescription: z
|
|
78
|
+
.string()
|
|
79
|
+
.min(1)
|
|
80
|
+
.max(120)
|
|
81
|
+
.refine((value) => value.trim().length > 0)
|
|
82
|
+
.optional(),
|
|
83
|
+
placeOfService: z.string().regex(new RegExp("^[0-9]{2}$")).optional(),
|
|
84
|
+
jurisdiction: z.string().min(1).max(80).optional(),
|
|
85
|
+
specialty: z.string().min(1).max(120).optional(),
|
|
86
|
+
provider: z
|
|
87
|
+
.object({
|
|
88
|
+
providerId: z.string().min(1).max(64).optional(),
|
|
89
|
+
npi: z.string().regex(new RegExp("^[0-9]{10}$")).optional(),
|
|
90
|
+
name: z.string().min(1).max(160).optional(),
|
|
91
|
+
role: z
|
|
92
|
+
.enum([
|
|
93
|
+
"rendering",
|
|
94
|
+
"billing",
|
|
95
|
+
"attending",
|
|
96
|
+
"supervising",
|
|
97
|
+
"ordering",
|
|
98
|
+
"referring",
|
|
99
|
+
"other",
|
|
100
|
+
])
|
|
101
|
+
.optional(),
|
|
102
|
+
taxonomy: z.string().min(1).max(40).optional(),
|
|
103
|
+
})
|
|
104
|
+
.strict()
|
|
105
|
+
.optional(),
|
|
106
|
+
facility: z
|
|
107
|
+
.object({
|
|
108
|
+
facilityId: z.string().min(1).max(64).optional(),
|
|
109
|
+
name: z.string().min(1).max(160).optional(),
|
|
110
|
+
facilityType: z
|
|
111
|
+
.enum([
|
|
112
|
+
"hospital_inpatient",
|
|
113
|
+
"hospital_outpatient",
|
|
114
|
+
"clinic",
|
|
115
|
+
"ambulatory_surgery_center",
|
|
116
|
+
"nursing_facility",
|
|
117
|
+
"other",
|
|
118
|
+
])
|
|
119
|
+
.optional(),
|
|
120
|
+
})
|
|
121
|
+
.strict()
|
|
122
|
+
.optional(),
|
|
123
|
+
})
|
|
124
|
+
.strict();
|
|
125
|
+
export function codingCaseContextValidationError(value) {
|
|
126
|
+
if (!isRecord(value))
|
|
127
|
+
return "context";
|
|
128
|
+
if (!["setting"].every((key) => key in value))
|
|
129
|
+
return "context_keys";
|
|
130
|
+
if (!Object.keys(value).every((key) => [
|
|
131
|
+
"setting",
|
|
132
|
+
"otherSettingDescription",
|
|
133
|
+
"placeOfService",
|
|
134
|
+
"jurisdiction",
|
|
135
|
+
"specialty",
|
|
136
|
+
"provider",
|
|
137
|
+
"facility",
|
|
138
|
+
].includes(key)))
|
|
139
|
+
return "context_keys";
|
|
140
|
+
const value_setting = value["setting"];
|
|
141
|
+
if (typeof value_setting !== "string" ||
|
|
142
|
+
![
|
|
143
|
+
"professional",
|
|
144
|
+
"facility",
|
|
145
|
+
"pharmacy",
|
|
146
|
+
"dental",
|
|
147
|
+
"risk_adjustment",
|
|
148
|
+
"other",
|
|
149
|
+
].includes(value_setting))
|
|
150
|
+
return "context_setting";
|
|
151
|
+
if (value["otherSettingDescription"] !== undefined) {
|
|
152
|
+
const value_otherSettingDescription = value["otherSettingDescription"];
|
|
153
|
+
if (typeof value_otherSettingDescription !== "string" ||
|
|
154
|
+
value_otherSettingDescription.length < 1 ||
|
|
155
|
+
value_otherSettingDescription.length > 120 ||
|
|
156
|
+
value_otherSettingDescription.trim().length === 0)
|
|
157
|
+
return "context_other_setting";
|
|
158
|
+
}
|
|
159
|
+
if (value["placeOfService"] !== undefined) {
|
|
160
|
+
const value_placeOfService = value["placeOfService"];
|
|
161
|
+
if (typeof value_placeOfService !== "string" ||
|
|
162
|
+
!new RegExp("^[0-9]{2}$").test(value_placeOfService))
|
|
163
|
+
return "context_place_of_service";
|
|
164
|
+
}
|
|
165
|
+
if (value["jurisdiction"] !== undefined) {
|
|
166
|
+
const value_jurisdiction = value["jurisdiction"];
|
|
167
|
+
if (typeof value_jurisdiction !== "string" ||
|
|
168
|
+
value_jurisdiction.length < 1 ||
|
|
169
|
+
value_jurisdiction.length > 80)
|
|
170
|
+
return "context_jurisdiction";
|
|
171
|
+
}
|
|
172
|
+
if (value["specialty"] !== undefined) {
|
|
173
|
+
const value_specialty = value["specialty"];
|
|
174
|
+
if (typeof value_specialty !== "string" ||
|
|
175
|
+
value_specialty.length < 1 ||
|
|
176
|
+
value_specialty.length > 120)
|
|
177
|
+
return "context_specialty";
|
|
178
|
+
}
|
|
179
|
+
if (value["provider"] !== undefined) {
|
|
180
|
+
const value_provider = value["provider"];
|
|
181
|
+
if (!isRecord(value_provider))
|
|
182
|
+
return "context_provider";
|
|
183
|
+
if (!Object.keys(value_provider).every((key) => ["providerId", "npi", "name", "role", "taxonomy"].includes(key)))
|
|
184
|
+
return "context_provider_keys";
|
|
185
|
+
if (value_provider["providerId"] !== undefined) {
|
|
186
|
+
const value_provider_providerId = value_provider["providerId"];
|
|
187
|
+
if (typeof value_provider_providerId !== "string" ||
|
|
188
|
+
value_provider_providerId.length < 1 ||
|
|
189
|
+
value_provider_providerId.length > 64)
|
|
190
|
+
return "context_provider_id";
|
|
191
|
+
}
|
|
192
|
+
if (value_provider["npi"] !== undefined) {
|
|
193
|
+
const value_provider_npi = value_provider["npi"];
|
|
194
|
+
if (typeof value_provider_npi !== "string" ||
|
|
195
|
+
!new RegExp("^[0-9]{10}$").test(value_provider_npi))
|
|
196
|
+
return "context_provider_npi";
|
|
197
|
+
}
|
|
198
|
+
if (value_provider["name"] !== undefined) {
|
|
199
|
+
const value_provider_name = value_provider["name"];
|
|
200
|
+
if (typeof value_provider_name !== "string" ||
|
|
201
|
+
value_provider_name.length < 1 ||
|
|
202
|
+
value_provider_name.length > 160)
|
|
203
|
+
return "context_provider_name";
|
|
204
|
+
}
|
|
205
|
+
if (value_provider["role"] !== undefined) {
|
|
206
|
+
const value_provider_role = value_provider["role"];
|
|
207
|
+
if (typeof value_provider_role !== "string" ||
|
|
208
|
+
![
|
|
209
|
+
"rendering",
|
|
210
|
+
"billing",
|
|
211
|
+
"attending",
|
|
212
|
+
"supervising",
|
|
213
|
+
"ordering",
|
|
214
|
+
"referring",
|
|
215
|
+
"other",
|
|
216
|
+
].includes(value_provider_role))
|
|
217
|
+
return "context_provider_role";
|
|
218
|
+
}
|
|
219
|
+
if (value_provider["taxonomy"] !== undefined) {
|
|
220
|
+
const value_provider_taxonomy = value_provider["taxonomy"];
|
|
221
|
+
if (typeof value_provider_taxonomy !== "string" ||
|
|
222
|
+
value_provider_taxonomy.length < 1 ||
|
|
223
|
+
value_provider_taxonomy.length > 40)
|
|
224
|
+
return "context_provider_taxonomy";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (value["facility"] !== undefined) {
|
|
228
|
+
const value_facility = value["facility"];
|
|
229
|
+
if (!isRecord(value_facility))
|
|
230
|
+
return "context_facility";
|
|
231
|
+
if (!Object.keys(value_facility).every((key) => ["facilityId", "name", "facilityType"].includes(key)))
|
|
232
|
+
return "context_facility_keys";
|
|
233
|
+
if (value_facility["facilityId"] !== undefined) {
|
|
234
|
+
const value_facility_facilityId = value_facility["facilityId"];
|
|
235
|
+
if (typeof value_facility_facilityId !== "string" ||
|
|
236
|
+
value_facility_facilityId.length < 1 ||
|
|
237
|
+
value_facility_facilityId.length > 64)
|
|
238
|
+
return "context_facility_id";
|
|
239
|
+
}
|
|
240
|
+
if (value_facility["name"] !== undefined) {
|
|
241
|
+
const value_facility_name = value_facility["name"];
|
|
242
|
+
if (typeof value_facility_name !== "string" ||
|
|
243
|
+
value_facility_name.length < 1 ||
|
|
244
|
+
value_facility_name.length > 160)
|
|
245
|
+
return "context_facility_name";
|
|
246
|
+
}
|
|
247
|
+
if (value_facility["facilityType"] !== undefined) {
|
|
248
|
+
const value_facility_facilityType = value_facility["facilityType"];
|
|
249
|
+
if (typeof value_facility_facilityType !== "string" ||
|
|
250
|
+
![
|
|
251
|
+
"hospital_inpatient",
|
|
252
|
+
"hospital_outpatient",
|
|
253
|
+
"clinic",
|
|
254
|
+
"ambulatory_surgery_center",
|
|
255
|
+
"nursing_facility",
|
|
256
|
+
"other",
|
|
257
|
+
].includes(value_facility_facilityType))
|
|
258
|
+
return "context_facility_type";
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
export const validCodingCaseContext = (value) => codingCaseContextValidationError(value) === null;
|
|
264
|
+
export const CodingCaseContextSchemaJson = {
|
|
265
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
266
|
+
$id: "https://nexalink.care/contracts/coding-case-context.schema.json",
|
|
267
|
+
title: "CodingCaseContext",
|
|
268
|
+
description: "Where and by whom the services were rendered: setting, place of service, jurisdiction, specialty, provider, and facility. Provider identifiers are direct identifiers and must never be promoted to analytics surfaces.",
|
|
269
|
+
version: "1.0.0",
|
|
270
|
+
type: "object",
|
|
271
|
+
additionalProperties: false,
|
|
272
|
+
required: ["setting"],
|
|
273
|
+
properties: {
|
|
274
|
+
setting: {
|
|
275
|
+
type: "string",
|
|
276
|
+
enum: [
|
|
277
|
+
"professional",
|
|
278
|
+
"facility",
|
|
279
|
+
"pharmacy",
|
|
280
|
+
"dental",
|
|
281
|
+
"risk_adjustment",
|
|
282
|
+
"other",
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
otherSettingDescription: {
|
|
286
|
+
type: "string",
|
|
287
|
+
minLength: 1,
|
|
288
|
+
maxLength: 120,
|
|
289
|
+
},
|
|
290
|
+
placeOfService: {
|
|
291
|
+
type: "string",
|
|
292
|
+
pattern: "^[0-9]{2}$",
|
|
293
|
+
},
|
|
294
|
+
jurisdiction: {
|
|
295
|
+
type: "string",
|
|
296
|
+
minLength: 1,
|
|
297
|
+
maxLength: 80,
|
|
298
|
+
},
|
|
299
|
+
specialty: {
|
|
300
|
+
type: "string",
|
|
301
|
+
minLength: 1,
|
|
302
|
+
maxLength: 120,
|
|
303
|
+
},
|
|
304
|
+
provider: {
|
|
305
|
+
type: "object",
|
|
306
|
+
additionalProperties: false,
|
|
307
|
+
properties: {
|
|
308
|
+
providerId: {
|
|
309
|
+
type: "string",
|
|
310
|
+
minLength: 1,
|
|
311
|
+
maxLength: 64,
|
|
312
|
+
},
|
|
313
|
+
npi: {
|
|
314
|
+
type: "string",
|
|
315
|
+
pattern: "^[0-9]{10}$",
|
|
316
|
+
},
|
|
317
|
+
name: {
|
|
318
|
+
type: "string",
|
|
319
|
+
minLength: 1,
|
|
320
|
+
maxLength: 160,
|
|
321
|
+
},
|
|
322
|
+
role: {
|
|
323
|
+
type: "string",
|
|
324
|
+
enum: [
|
|
325
|
+
"rendering",
|
|
326
|
+
"billing",
|
|
327
|
+
"attending",
|
|
328
|
+
"supervising",
|
|
329
|
+
"ordering",
|
|
330
|
+
"referring",
|
|
331
|
+
"other",
|
|
332
|
+
],
|
|
333
|
+
},
|
|
334
|
+
taxonomy: {
|
|
335
|
+
type: "string",
|
|
336
|
+
minLength: 1,
|
|
337
|
+
maxLength: 40,
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
facility: {
|
|
342
|
+
type: "object",
|
|
343
|
+
additionalProperties: false,
|
|
344
|
+
properties: {
|
|
345
|
+
facilityId: {
|
|
346
|
+
type: "string",
|
|
347
|
+
minLength: 1,
|
|
348
|
+
maxLength: 64,
|
|
349
|
+
},
|
|
350
|
+
name: {
|
|
351
|
+
type: "string",
|
|
352
|
+
minLength: 1,
|
|
353
|
+
maxLength: 160,
|
|
354
|
+
},
|
|
355
|
+
facilityType: {
|
|
356
|
+
type: "string",
|
|
357
|
+
enum: [
|
|
358
|
+
"hospital_inpatient",
|
|
359
|
+
"hospital_outpatient",
|
|
360
|
+
"clinic",
|
|
361
|
+
"ambulatory_surgery_center",
|
|
362
|
+
"nursing_facility",
|
|
363
|
+
"other",
|
|
364
|
+
],
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
// --------------------------------------------------------------------
|
|
371
|
+
// CodingCasePayer (schema 1.0.0, wire coding-case-payer-v1)
|
|
372
|
+
// --------------------------------------------------------------------
|
|
373
|
+
export const codingCasePayerSchema = z
|
|
374
|
+
.object({
|
|
375
|
+
payerName: z
|
|
376
|
+
.string()
|
|
377
|
+
.min(1)
|
|
378
|
+
.max(200)
|
|
379
|
+
.refine((value) => value.trim().length > 0),
|
|
380
|
+
payerId: z.string().min(1).max(120).optional(),
|
|
381
|
+
lineOfBusiness: z
|
|
382
|
+
.enum(["commercial", "government", "self_pay", "other"])
|
|
383
|
+
.optional(),
|
|
384
|
+
memberId: z.string().min(1).max(120).optional(),
|
|
385
|
+
plan: z
|
|
386
|
+
.object({
|
|
387
|
+
planName: z.string().min(1).max(200).optional(),
|
|
388
|
+
planId: z.string().min(1).max(120).optional(),
|
|
389
|
+
})
|
|
390
|
+
.strict()
|
|
391
|
+
.optional(),
|
|
392
|
+
program: z
|
|
393
|
+
.object({
|
|
394
|
+
programName: z.string().min(1).max(160).optional(),
|
|
395
|
+
programCode: z.string().min(1).max(80).optional(),
|
|
396
|
+
})
|
|
397
|
+
.strict()
|
|
398
|
+
.optional(),
|
|
399
|
+
contract: z
|
|
400
|
+
.object({
|
|
401
|
+
contractId: z.string().min(1).max(120).optional(),
|
|
402
|
+
contractVersion: z.string().min(1).max(40).optional(),
|
|
403
|
+
effectiveDate: z
|
|
404
|
+
.string()
|
|
405
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
406
|
+
.refine(isIsoDate)
|
|
407
|
+
.optional(),
|
|
408
|
+
})
|
|
409
|
+
.strict()
|
|
410
|
+
.optional(),
|
|
411
|
+
mac: z
|
|
412
|
+
.object({
|
|
413
|
+
macId: z.string().min(1).max(40).optional(),
|
|
414
|
+
jurisdiction: z.string().min(1).max(80).optional(),
|
|
415
|
+
})
|
|
416
|
+
.strict()
|
|
417
|
+
.optional(),
|
|
418
|
+
})
|
|
419
|
+
.strict();
|
|
420
|
+
export function codingCasePayerValidationError(value) {
|
|
421
|
+
if (!isRecord(value))
|
|
422
|
+
return "payer";
|
|
423
|
+
if (!["payerName"].every((key) => key in value))
|
|
424
|
+
return "payer_keys";
|
|
425
|
+
if (!Object.keys(value).every((key) => [
|
|
426
|
+
"payerName",
|
|
427
|
+
"payerId",
|
|
428
|
+
"lineOfBusiness",
|
|
429
|
+
"memberId",
|
|
430
|
+
"plan",
|
|
431
|
+
"program",
|
|
432
|
+
"contract",
|
|
433
|
+
"mac",
|
|
434
|
+
].includes(key)))
|
|
435
|
+
return "payer_keys";
|
|
436
|
+
const value_payerName = value["payerName"];
|
|
437
|
+
if (typeof value_payerName !== "string" ||
|
|
438
|
+
value_payerName.length < 1 ||
|
|
439
|
+
value_payerName.length > 200 ||
|
|
440
|
+
value_payerName.trim().length === 0)
|
|
441
|
+
return "payer_name";
|
|
442
|
+
if (value["payerId"] !== undefined) {
|
|
443
|
+
const value_payerId = value["payerId"];
|
|
444
|
+
if (typeof value_payerId !== "string" ||
|
|
445
|
+
value_payerId.length < 1 ||
|
|
446
|
+
value_payerId.length > 120)
|
|
447
|
+
return "payer_id";
|
|
448
|
+
}
|
|
449
|
+
if (value["lineOfBusiness"] !== undefined) {
|
|
450
|
+
const value_lineOfBusiness = value["lineOfBusiness"];
|
|
451
|
+
if (typeof value_lineOfBusiness !== "string" ||
|
|
452
|
+
!["commercial", "government", "self_pay", "other"].includes(value_lineOfBusiness))
|
|
453
|
+
return "payer_line_of_business";
|
|
454
|
+
}
|
|
455
|
+
if (value["memberId"] !== undefined) {
|
|
456
|
+
const value_memberId = value["memberId"];
|
|
457
|
+
if (typeof value_memberId !== "string" ||
|
|
458
|
+
value_memberId.length < 1 ||
|
|
459
|
+
value_memberId.length > 120)
|
|
460
|
+
return "payer_member_id";
|
|
461
|
+
}
|
|
462
|
+
if (value["plan"] !== undefined) {
|
|
463
|
+
const value_plan = value["plan"];
|
|
464
|
+
if (!isRecord(value_plan))
|
|
465
|
+
return "payer_plan";
|
|
466
|
+
if (!Object.keys(value_plan).every((key) => ["planName", "planId"].includes(key)))
|
|
467
|
+
return "payer_plan_keys";
|
|
468
|
+
if (value_plan["planName"] !== undefined) {
|
|
469
|
+
const value_plan_planName = value_plan["planName"];
|
|
470
|
+
if (typeof value_plan_planName !== "string" ||
|
|
471
|
+
value_plan_planName.length < 1 ||
|
|
472
|
+
value_plan_planName.length > 200)
|
|
473
|
+
return "payer_plan_name";
|
|
474
|
+
}
|
|
475
|
+
if (value_plan["planId"] !== undefined) {
|
|
476
|
+
const value_plan_planId = value_plan["planId"];
|
|
477
|
+
if (typeof value_plan_planId !== "string" ||
|
|
478
|
+
value_plan_planId.length < 1 ||
|
|
479
|
+
value_plan_planId.length > 120)
|
|
480
|
+
return "payer_plan_id";
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (value["program"] !== undefined) {
|
|
484
|
+
const value_program = value["program"];
|
|
485
|
+
if (!isRecord(value_program))
|
|
486
|
+
return "payer_program";
|
|
487
|
+
if (!Object.keys(value_program).every((key) => ["programName", "programCode"].includes(key)))
|
|
488
|
+
return "payer_program_keys";
|
|
489
|
+
if (value_program["programName"] !== undefined) {
|
|
490
|
+
const value_program_programName = value_program["programName"];
|
|
491
|
+
if (typeof value_program_programName !== "string" ||
|
|
492
|
+
value_program_programName.length < 1 ||
|
|
493
|
+
value_program_programName.length > 160)
|
|
494
|
+
return "payer_program_name";
|
|
495
|
+
}
|
|
496
|
+
if (value_program["programCode"] !== undefined) {
|
|
497
|
+
const value_program_programCode = value_program["programCode"];
|
|
498
|
+
if (typeof value_program_programCode !== "string" ||
|
|
499
|
+
value_program_programCode.length < 1 ||
|
|
500
|
+
value_program_programCode.length > 80)
|
|
501
|
+
return "payer_program_code";
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (value["contract"] !== undefined) {
|
|
505
|
+
const value_contract = value["contract"];
|
|
506
|
+
if (!isRecord(value_contract))
|
|
507
|
+
return "payer_contract";
|
|
508
|
+
if (!Object.keys(value_contract).every((key) => ["contractId", "contractVersion", "effectiveDate"].includes(key)))
|
|
509
|
+
return "payer_contract_keys";
|
|
510
|
+
if (value_contract["contractId"] !== undefined) {
|
|
511
|
+
const value_contract_contractId = value_contract["contractId"];
|
|
512
|
+
if (typeof value_contract_contractId !== "string" ||
|
|
513
|
+
value_contract_contractId.length < 1 ||
|
|
514
|
+
value_contract_contractId.length > 120)
|
|
515
|
+
return "payer_contract_id";
|
|
516
|
+
}
|
|
517
|
+
if (value_contract["contractVersion"] !== undefined) {
|
|
518
|
+
const value_contract_contractVersion = value_contract["contractVersion"];
|
|
519
|
+
if (typeof value_contract_contractVersion !== "string" ||
|
|
520
|
+
value_contract_contractVersion.length < 1 ||
|
|
521
|
+
value_contract_contractVersion.length > 40)
|
|
522
|
+
return "payer_contract_version";
|
|
523
|
+
}
|
|
524
|
+
if (value_contract["effectiveDate"] !== undefined) {
|
|
525
|
+
const value_contract_effectiveDate = value_contract["effectiveDate"];
|
|
526
|
+
if (typeof value_contract_effectiveDate !== "string" ||
|
|
527
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_contract_effectiveDate) ||
|
|
528
|
+
!isIsoDate(value_contract_effectiveDate))
|
|
529
|
+
return "payer_contract_effective_date";
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (value["mac"] !== undefined) {
|
|
533
|
+
const value_mac = value["mac"];
|
|
534
|
+
if (!isRecord(value_mac))
|
|
535
|
+
return "payer_mac";
|
|
536
|
+
if (!Object.keys(value_mac).every((key) => ["macId", "jurisdiction"].includes(key)))
|
|
537
|
+
return "payer_mac_keys";
|
|
538
|
+
if (value_mac["macId"] !== undefined) {
|
|
539
|
+
const value_mac_macId = value_mac["macId"];
|
|
540
|
+
if (typeof value_mac_macId !== "string" ||
|
|
541
|
+
value_mac_macId.length < 1 ||
|
|
542
|
+
value_mac_macId.length > 40)
|
|
543
|
+
return "payer_mac_id";
|
|
544
|
+
}
|
|
545
|
+
if (value_mac["jurisdiction"] !== undefined) {
|
|
546
|
+
const value_mac_jurisdiction = value_mac["jurisdiction"];
|
|
547
|
+
if (typeof value_mac_jurisdiction !== "string" ||
|
|
548
|
+
value_mac_jurisdiction.length < 1 ||
|
|
549
|
+
value_mac_jurisdiction.length > 80)
|
|
550
|
+
return "payer_mac_jurisdiction";
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
export const validCodingCasePayer = (value) => codingCasePayerValidationError(value) === null;
|
|
556
|
+
export const CodingCasePayerSchemaJson = {
|
|
557
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
558
|
+
$id: "https://nexalink.care/contracts/coding-case-payer.schema.json",
|
|
559
|
+
title: "CodingCasePayer",
|
|
560
|
+
description: "Payer, plan, program, contract, and MAC context used to resolve applicability. memberId is a direct identifier and must never leave tenant-scoped storage for analytics surfaces. Contract and program fields are customer configuration, never immutable server policy.",
|
|
561
|
+
version: "1.0.0",
|
|
562
|
+
type: "object",
|
|
563
|
+
additionalProperties: false,
|
|
564
|
+
required: ["payerName"],
|
|
565
|
+
properties: {
|
|
566
|
+
payerName: {
|
|
567
|
+
type: "string",
|
|
568
|
+
minLength: 1,
|
|
569
|
+
maxLength: 200,
|
|
570
|
+
},
|
|
571
|
+
payerId: {
|
|
572
|
+
type: "string",
|
|
573
|
+
minLength: 1,
|
|
574
|
+
maxLength: 120,
|
|
575
|
+
},
|
|
576
|
+
lineOfBusiness: {
|
|
577
|
+
type: "string",
|
|
578
|
+
enum: ["commercial", "government", "self_pay", "other"],
|
|
579
|
+
},
|
|
580
|
+
memberId: {
|
|
581
|
+
type: "string",
|
|
582
|
+
minLength: 1,
|
|
583
|
+
maxLength: 120,
|
|
584
|
+
},
|
|
585
|
+
plan: {
|
|
586
|
+
type: "object",
|
|
587
|
+
additionalProperties: false,
|
|
588
|
+
properties: {
|
|
589
|
+
planName: {
|
|
590
|
+
type: "string",
|
|
591
|
+
minLength: 1,
|
|
592
|
+
maxLength: 200,
|
|
593
|
+
},
|
|
594
|
+
planId: {
|
|
595
|
+
type: "string",
|
|
596
|
+
minLength: 1,
|
|
597
|
+
maxLength: 120,
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
program: {
|
|
602
|
+
type: "object",
|
|
603
|
+
additionalProperties: false,
|
|
604
|
+
properties: {
|
|
605
|
+
programName: {
|
|
606
|
+
type: "string",
|
|
607
|
+
minLength: 1,
|
|
608
|
+
maxLength: 160,
|
|
609
|
+
},
|
|
610
|
+
programCode: {
|
|
611
|
+
type: "string",
|
|
612
|
+
minLength: 1,
|
|
613
|
+
maxLength: 80,
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
contract: {
|
|
618
|
+
type: "object",
|
|
619
|
+
additionalProperties: false,
|
|
620
|
+
properties: {
|
|
621
|
+
contractId: {
|
|
622
|
+
type: "string",
|
|
623
|
+
minLength: 1,
|
|
624
|
+
maxLength: 120,
|
|
625
|
+
},
|
|
626
|
+
contractVersion: {
|
|
627
|
+
type: "string",
|
|
628
|
+
minLength: 1,
|
|
629
|
+
maxLength: 40,
|
|
630
|
+
},
|
|
631
|
+
effectiveDate: {
|
|
632
|
+
type: "string",
|
|
633
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
634
|
+
format: "date",
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
mac: {
|
|
639
|
+
type: "object",
|
|
640
|
+
additionalProperties: false,
|
|
641
|
+
properties: {
|
|
642
|
+
macId: {
|
|
643
|
+
type: "string",
|
|
644
|
+
minLength: 1,
|
|
645
|
+
maxLength: 40,
|
|
646
|
+
},
|
|
647
|
+
jurisdiction: {
|
|
648
|
+
type: "string",
|
|
649
|
+
minLength: 1,
|
|
650
|
+
maxLength: 80,
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
},
|
|
655
|
+
};
|
|
656
|
+
// --------------------------------------------------------------------
|
|
657
|
+
// CodingCaseClinical (schema 1.0.0, wire coding-case-clinical-v1)
|
|
658
|
+
// --------------------------------------------------------------------
|
|
659
|
+
export const codingCaseClinicalSchema = z
|
|
660
|
+
.object({
|
|
661
|
+
diagnoses: z
|
|
662
|
+
.array(z
|
|
663
|
+
.object({
|
|
664
|
+
diagnosisId: z.string().min(1).max(60),
|
|
665
|
+
code: z.string().min(1).max(32).optional(),
|
|
666
|
+
codeSystem: z.enum(["ICD-10-CM", "ICD-9-CM", "OTHER"]).optional(),
|
|
667
|
+
codeVersion: z.string().min(1).max(40).optional(),
|
|
668
|
+
description: z.string().min(1).max(240).optional(),
|
|
669
|
+
diagnosisType: z
|
|
670
|
+
.enum(["principal", "secondary", "complication", "other"])
|
|
671
|
+
.optional(),
|
|
672
|
+
onsetDate: z
|
|
673
|
+
.string()
|
|
674
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
675
|
+
.refine(isIsoDate)
|
|
676
|
+
.optional(),
|
|
677
|
+
presentOnAdmission: z.boolean().optional(),
|
|
678
|
+
})
|
|
679
|
+
.strict())
|
|
680
|
+
.max(100)
|
|
681
|
+
.optional(),
|
|
682
|
+
procedures: z
|
|
683
|
+
.array(z
|
|
684
|
+
.object({
|
|
685
|
+
procedureId: z.string().min(1).max(60),
|
|
686
|
+
code: z.string().min(1).max(64).optional(),
|
|
687
|
+
codeSystem: z
|
|
688
|
+
.enum(["CPT", "HCPCS", "ICD-10-PCS", "OTHER"])
|
|
689
|
+
.optional(),
|
|
690
|
+
codeVersion: z.string().min(1).max(40).optional(),
|
|
691
|
+
description: z.string().min(1).max(240).optional(),
|
|
692
|
+
performedDate: z
|
|
693
|
+
.string()
|
|
694
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
695
|
+
.refine(isIsoDate)
|
|
696
|
+
.optional(),
|
|
697
|
+
})
|
|
698
|
+
.strict())
|
|
699
|
+
.max(100)
|
|
700
|
+
.optional(),
|
|
701
|
+
medications: z
|
|
702
|
+
.array(z
|
|
703
|
+
.object({
|
|
704
|
+
medicationId: z.string().min(1).max(60),
|
|
705
|
+
code: z.string().min(1).max(64).optional(),
|
|
706
|
+
codeSystem: z.enum(["NDC", "RxNorm", "OTHER"]).optional(),
|
|
707
|
+
name: z.string().min(1).max(240).optional(),
|
|
708
|
+
dosage: z.string().min(1).max(120).optional(),
|
|
709
|
+
route: z.string().min(1).max(80).optional(),
|
|
710
|
+
administrationDate: z
|
|
711
|
+
.string()
|
|
712
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
713
|
+
.refine(isIsoDate)
|
|
714
|
+
.optional(),
|
|
715
|
+
})
|
|
716
|
+
.strict())
|
|
717
|
+
.max(100)
|
|
718
|
+
.optional(),
|
|
719
|
+
supplies: z
|
|
720
|
+
.array(z
|
|
721
|
+
.object({
|
|
722
|
+
supplyId: z.string().min(1).max(60),
|
|
723
|
+
code: z.string().min(1).max(64).optional(),
|
|
724
|
+
codeSystem: z.enum(["HCPCS", "NDC", "OTHER"]).optional(),
|
|
725
|
+
name: z.string().min(1).max(240).optional(),
|
|
726
|
+
quantity: z.number().int().min(0).max(999999).optional(),
|
|
727
|
+
unitOfMeasure: z.string().min(1).max(20).optional(),
|
|
728
|
+
supplyDate: z
|
|
729
|
+
.string()
|
|
730
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
731
|
+
.refine(isIsoDate)
|
|
732
|
+
.optional(),
|
|
733
|
+
})
|
|
734
|
+
.strict())
|
|
735
|
+
.max(100)
|
|
736
|
+
.optional(),
|
|
737
|
+
timeUnits: z
|
|
738
|
+
.array(z
|
|
739
|
+
.object({
|
|
740
|
+
timeId: z.string().min(1).max(60),
|
|
741
|
+
date: z
|
|
742
|
+
.string()
|
|
743
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
744
|
+
.refine(isIsoDate),
|
|
745
|
+
durationMinutes: z.number().int().min(1).max(1440),
|
|
746
|
+
activityCode: z.string().min(1).max(80).optional(),
|
|
747
|
+
activityDescription: z.string().min(1).max(240).optional(),
|
|
748
|
+
clinicianRole: z
|
|
749
|
+
.enum([
|
|
750
|
+
"attending",
|
|
751
|
+
"physician",
|
|
752
|
+
"nurse_practitioner",
|
|
753
|
+
"physician_assistant",
|
|
754
|
+
"resident",
|
|
755
|
+
"other",
|
|
756
|
+
])
|
|
757
|
+
.optional(),
|
|
758
|
+
placeOfService: z
|
|
759
|
+
.string()
|
|
760
|
+
.regex(new RegExp("^[0-9]{2}$"))
|
|
761
|
+
.optional(),
|
|
762
|
+
})
|
|
763
|
+
.strict())
|
|
764
|
+
.max(200)
|
|
765
|
+
.optional(),
|
|
766
|
+
notes: z
|
|
767
|
+
.array(z
|
|
768
|
+
.object({
|
|
769
|
+
noteId: z.string().min(1).max(60),
|
|
770
|
+
noteType: z.enum([
|
|
771
|
+
"clinical_narrative",
|
|
772
|
+
"procedure_narrative",
|
|
773
|
+
"authorization",
|
|
774
|
+
"correspondence",
|
|
775
|
+
"other",
|
|
776
|
+
]),
|
|
777
|
+
note: z
|
|
778
|
+
.string()
|
|
779
|
+
.min(1)
|
|
780
|
+
.max(10000)
|
|
781
|
+
.refine((value) => value.trim().length > 0),
|
|
782
|
+
})
|
|
783
|
+
.strict())
|
|
784
|
+
.max(50)
|
|
785
|
+
.optional(),
|
|
786
|
+
sourceReferences: z
|
|
787
|
+
.array(z
|
|
788
|
+
.object({
|
|
789
|
+
sourceId: z.string().min(1).max(60),
|
|
790
|
+
sourceLabel: z.string().min(1).max(120),
|
|
791
|
+
documentId: z.string().min(1).max(240).optional(),
|
|
792
|
+
excerpt: z
|
|
793
|
+
.string()
|
|
794
|
+
.min(1)
|
|
795
|
+
.max(2000)
|
|
796
|
+
.refine((value) => value.trim().length > 0)
|
|
797
|
+
.optional(),
|
|
798
|
+
sourceVersion: z.string().min(1).max(80).optional(),
|
|
799
|
+
corpusScope: z.enum(["base", "tenant"]).optional(),
|
|
800
|
+
publisher: z.string().min(1).max(240).optional(),
|
|
801
|
+
effectiveDate: z
|
|
802
|
+
.string()
|
|
803
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
804
|
+
.refine(isIsoDate)
|
|
805
|
+
.optional(),
|
|
806
|
+
retrievalDate: z
|
|
807
|
+
.string()
|
|
808
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
809
|
+
.refine(isIsoDate)
|
|
810
|
+
.optional(),
|
|
811
|
+
coveredPayerProgram: z.string().min(1).max(240).optional(),
|
|
812
|
+
sourceUrl: z.string().min(1).max(2048).optional(),
|
|
813
|
+
documentHash: z.string().min(1).max(64).optional(),
|
|
814
|
+
capturedAt: z
|
|
815
|
+
.string()
|
|
816
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
817
|
+
.refine(isIsoDate)
|
|
818
|
+
.optional(),
|
|
819
|
+
humanReviewRequired: z.literal(true).optional(),
|
|
820
|
+
})
|
|
821
|
+
.strict())
|
|
822
|
+
.max(50)
|
|
823
|
+
.optional(),
|
|
824
|
+
})
|
|
825
|
+
.strict();
|
|
826
|
+
export function codingCaseClinicalValidationError(value) {
|
|
827
|
+
if (!isRecord(value))
|
|
828
|
+
return "clinical";
|
|
829
|
+
if (!Object.keys(value).every((key) => [
|
|
830
|
+
"diagnoses",
|
|
831
|
+
"procedures",
|
|
832
|
+
"medications",
|
|
833
|
+
"supplies",
|
|
834
|
+
"timeUnits",
|
|
835
|
+
"notes",
|
|
836
|
+
"sourceReferences",
|
|
837
|
+
].includes(key)))
|
|
838
|
+
return "clinical_keys";
|
|
839
|
+
if (value["diagnoses"] !== undefined) {
|
|
840
|
+
const value_diagnoses = value["diagnoses"];
|
|
841
|
+
if (!Array.isArray(value_diagnoses) || value_diagnoses.length > 100)
|
|
842
|
+
return "clinical_diagnoses";
|
|
843
|
+
for (const item of value_diagnoses) {
|
|
844
|
+
if (!isRecord(item))
|
|
845
|
+
return "clinical_diagnosis";
|
|
846
|
+
if (!["diagnosisId"].every((key) => key in item))
|
|
847
|
+
return "clinical_diagnosis_keys";
|
|
848
|
+
if (!Object.keys(item).every((key) => [
|
|
849
|
+
"diagnosisId",
|
|
850
|
+
"code",
|
|
851
|
+
"codeSystem",
|
|
852
|
+
"codeVersion",
|
|
853
|
+
"description",
|
|
854
|
+
"diagnosisType",
|
|
855
|
+
"onsetDate",
|
|
856
|
+
"presentOnAdmission",
|
|
857
|
+
].includes(key)))
|
|
858
|
+
return "clinical_diagnosis_keys";
|
|
859
|
+
const item_diagnosisId = item["diagnosisId"];
|
|
860
|
+
if (typeof item_diagnosisId !== "string" ||
|
|
861
|
+
item_diagnosisId.length < 1 ||
|
|
862
|
+
item_diagnosisId.length > 60)
|
|
863
|
+
return "clinical_diagnosis_id";
|
|
864
|
+
if (item["code"] !== undefined) {
|
|
865
|
+
const item_code = item["code"];
|
|
866
|
+
if (typeof item_code !== "string" ||
|
|
867
|
+
item_code.length < 1 ||
|
|
868
|
+
item_code.length > 32)
|
|
869
|
+
return "clinical_diagnosis_code";
|
|
870
|
+
}
|
|
871
|
+
if (item["codeSystem"] !== undefined) {
|
|
872
|
+
const item_codeSystem = item["codeSystem"];
|
|
873
|
+
if (typeof item_codeSystem !== "string" ||
|
|
874
|
+
!["ICD-10-CM", "ICD-9-CM", "OTHER"].includes(item_codeSystem))
|
|
875
|
+
return "clinical_diagnosis_code_system";
|
|
876
|
+
}
|
|
877
|
+
if (item["codeVersion"] !== undefined) {
|
|
878
|
+
const item_codeVersion = item["codeVersion"];
|
|
879
|
+
if (typeof item_codeVersion !== "string" ||
|
|
880
|
+
item_codeVersion.length < 1 ||
|
|
881
|
+
item_codeVersion.length > 40)
|
|
882
|
+
return "clinical_diagnosis_code_version";
|
|
883
|
+
}
|
|
884
|
+
if (item["description"] !== undefined) {
|
|
885
|
+
const item_description = item["description"];
|
|
886
|
+
if (typeof item_description !== "string" ||
|
|
887
|
+
item_description.length < 1 ||
|
|
888
|
+
item_description.length > 240)
|
|
889
|
+
return "clinical_diagnosis_description";
|
|
890
|
+
}
|
|
891
|
+
if (item["diagnosisType"] !== undefined) {
|
|
892
|
+
const item_diagnosisType = item["diagnosisType"];
|
|
893
|
+
if (typeof item_diagnosisType !== "string" ||
|
|
894
|
+
!["principal", "secondary", "complication", "other"].includes(item_diagnosisType))
|
|
895
|
+
return "clinical_diagnosis_type";
|
|
896
|
+
}
|
|
897
|
+
if (item["onsetDate"] !== undefined) {
|
|
898
|
+
const item_onsetDate = item["onsetDate"];
|
|
899
|
+
if (typeof item_onsetDate !== "string" ||
|
|
900
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_onsetDate) ||
|
|
901
|
+
!isIsoDate(item_onsetDate))
|
|
902
|
+
return "clinical_diagnosis_onset_date";
|
|
903
|
+
}
|
|
904
|
+
if (item["presentOnAdmission"] !== undefined) {
|
|
905
|
+
const item_presentOnAdmission = item["presentOnAdmission"];
|
|
906
|
+
if (typeof item_presentOnAdmission !== "boolean")
|
|
907
|
+
return "clinical_diagnosis_present_on_admission";
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (value["procedures"] !== undefined) {
|
|
912
|
+
const value_procedures = value["procedures"];
|
|
913
|
+
if (!Array.isArray(value_procedures) || value_procedures.length > 100)
|
|
914
|
+
return "clinical_procedures";
|
|
915
|
+
for (const item of value_procedures) {
|
|
916
|
+
if (!isRecord(item))
|
|
917
|
+
return "clinical_procedure";
|
|
918
|
+
if (!["procedureId"].every((key) => key in item))
|
|
919
|
+
return "clinical_procedure_keys";
|
|
920
|
+
if (!Object.keys(item).every((key) => [
|
|
921
|
+
"procedureId",
|
|
922
|
+
"code",
|
|
923
|
+
"codeSystem",
|
|
924
|
+
"codeVersion",
|
|
925
|
+
"description",
|
|
926
|
+
"performedDate",
|
|
927
|
+
].includes(key)))
|
|
928
|
+
return "clinical_procedure_keys";
|
|
929
|
+
const item_procedureId = item["procedureId"];
|
|
930
|
+
if (typeof item_procedureId !== "string" ||
|
|
931
|
+
item_procedureId.length < 1 ||
|
|
932
|
+
item_procedureId.length > 60)
|
|
933
|
+
return "clinical_procedure_id";
|
|
934
|
+
if (item["code"] !== undefined) {
|
|
935
|
+
const item_code = item["code"];
|
|
936
|
+
if (typeof item_code !== "string" ||
|
|
937
|
+
item_code.length < 1 ||
|
|
938
|
+
item_code.length > 64)
|
|
939
|
+
return "clinical_procedure_code";
|
|
940
|
+
}
|
|
941
|
+
if (item["codeSystem"] !== undefined) {
|
|
942
|
+
const item_codeSystem = item["codeSystem"];
|
|
943
|
+
if (typeof item_codeSystem !== "string" ||
|
|
944
|
+
!["CPT", "HCPCS", "ICD-10-PCS", "OTHER"].includes(item_codeSystem))
|
|
945
|
+
return "clinical_procedure_code_system";
|
|
946
|
+
}
|
|
947
|
+
if (item["codeVersion"] !== undefined) {
|
|
948
|
+
const item_codeVersion = item["codeVersion"];
|
|
949
|
+
if (typeof item_codeVersion !== "string" ||
|
|
950
|
+
item_codeVersion.length < 1 ||
|
|
951
|
+
item_codeVersion.length > 40)
|
|
952
|
+
return "clinical_procedure_code_version";
|
|
953
|
+
}
|
|
954
|
+
if (item["description"] !== undefined) {
|
|
955
|
+
const item_description = item["description"];
|
|
956
|
+
if (typeof item_description !== "string" ||
|
|
957
|
+
item_description.length < 1 ||
|
|
958
|
+
item_description.length > 240)
|
|
959
|
+
return "clinical_procedure_description";
|
|
960
|
+
}
|
|
961
|
+
if (item["performedDate"] !== undefined) {
|
|
962
|
+
const item_performedDate = item["performedDate"];
|
|
963
|
+
if (typeof item_performedDate !== "string" ||
|
|
964
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_performedDate) ||
|
|
965
|
+
!isIsoDate(item_performedDate))
|
|
966
|
+
return "clinical_procedure_performed_date";
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
if (value["medications"] !== undefined) {
|
|
971
|
+
const value_medications = value["medications"];
|
|
972
|
+
if (!Array.isArray(value_medications) || value_medications.length > 100)
|
|
973
|
+
return "clinical_medications";
|
|
974
|
+
for (const item of value_medications) {
|
|
975
|
+
if (!isRecord(item))
|
|
976
|
+
return "clinical_medication";
|
|
977
|
+
if (!["medicationId"].every((key) => key in item))
|
|
978
|
+
return "clinical_medication_keys";
|
|
979
|
+
if (!Object.keys(item).every((key) => [
|
|
980
|
+
"medicationId",
|
|
981
|
+
"code",
|
|
982
|
+
"codeSystem",
|
|
983
|
+
"name",
|
|
984
|
+
"dosage",
|
|
985
|
+
"route",
|
|
986
|
+
"administrationDate",
|
|
987
|
+
].includes(key)))
|
|
988
|
+
return "clinical_medication_keys";
|
|
989
|
+
const item_medicationId = item["medicationId"];
|
|
990
|
+
if (typeof item_medicationId !== "string" ||
|
|
991
|
+
item_medicationId.length < 1 ||
|
|
992
|
+
item_medicationId.length > 60)
|
|
993
|
+
return "clinical_medication_id";
|
|
994
|
+
if (item["code"] !== undefined) {
|
|
995
|
+
const item_code = item["code"];
|
|
996
|
+
if (typeof item_code !== "string" ||
|
|
997
|
+
item_code.length < 1 ||
|
|
998
|
+
item_code.length > 64)
|
|
999
|
+
return "clinical_medication_code";
|
|
1000
|
+
}
|
|
1001
|
+
if (item["codeSystem"] !== undefined) {
|
|
1002
|
+
const item_codeSystem = item["codeSystem"];
|
|
1003
|
+
if (typeof item_codeSystem !== "string" ||
|
|
1004
|
+
!["NDC", "RxNorm", "OTHER"].includes(item_codeSystem))
|
|
1005
|
+
return "clinical_medication_code_system";
|
|
1006
|
+
}
|
|
1007
|
+
if (item["name"] !== undefined) {
|
|
1008
|
+
const item_name = item["name"];
|
|
1009
|
+
if (typeof item_name !== "string" ||
|
|
1010
|
+
item_name.length < 1 ||
|
|
1011
|
+
item_name.length > 240)
|
|
1012
|
+
return "clinical_medication_name";
|
|
1013
|
+
}
|
|
1014
|
+
if (item["dosage"] !== undefined) {
|
|
1015
|
+
const item_dosage = item["dosage"];
|
|
1016
|
+
if (typeof item_dosage !== "string" ||
|
|
1017
|
+
item_dosage.length < 1 ||
|
|
1018
|
+
item_dosage.length > 120)
|
|
1019
|
+
return "clinical_medication_dosage";
|
|
1020
|
+
}
|
|
1021
|
+
if (item["route"] !== undefined) {
|
|
1022
|
+
const item_route = item["route"];
|
|
1023
|
+
if (typeof item_route !== "string" ||
|
|
1024
|
+
item_route.length < 1 ||
|
|
1025
|
+
item_route.length > 80)
|
|
1026
|
+
return "clinical_medication_route";
|
|
1027
|
+
}
|
|
1028
|
+
if (item["administrationDate"] !== undefined) {
|
|
1029
|
+
const item_administrationDate = item["administrationDate"];
|
|
1030
|
+
if (typeof item_administrationDate !== "string" ||
|
|
1031
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_administrationDate) ||
|
|
1032
|
+
!isIsoDate(item_administrationDate))
|
|
1033
|
+
return "clinical_medication_administration_date";
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
if (value["supplies"] !== undefined) {
|
|
1038
|
+
const value_supplies = value["supplies"];
|
|
1039
|
+
if (!Array.isArray(value_supplies) || value_supplies.length > 100)
|
|
1040
|
+
return "clinical_supplies";
|
|
1041
|
+
for (const item of value_supplies) {
|
|
1042
|
+
if (!isRecord(item))
|
|
1043
|
+
return "clinical_supply";
|
|
1044
|
+
if (!["supplyId"].every((key) => key in item))
|
|
1045
|
+
return "clinical_supply_keys";
|
|
1046
|
+
if (!Object.keys(item).every((key) => [
|
|
1047
|
+
"supplyId",
|
|
1048
|
+
"code",
|
|
1049
|
+
"codeSystem",
|
|
1050
|
+
"name",
|
|
1051
|
+
"quantity",
|
|
1052
|
+
"unitOfMeasure",
|
|
1053
|
+
"supplyDate",
|
|
1054
|
+
].includes(key)))
|
|
1055
|
+
return "clinical_supply_keys";
|
|
1056
|
+
const item_supplyId = item["supplyId"];
|
|
1057
|
+
if (typeof item_supplyId !== "string" ||
|
|
1058
|
+
item_supplyId.length < 1 ||
|
|
1059
|
+
item_supplyId.length > 60)
|
|
1060
|
+
return "clinical_supply_id";
|
|
1061
|
+
if (item["code"] !== undefined) {
|
|
1062
|
+
const item_code = item["code"];
|
|
1063
|
+
if (typeof item_code !== "string" ||
|
|
1064
|
+
item_code.length < 1 ||
|
|
1065
|
+
item_code.length > 64)
|
|
1066
|
+
return "clinical_supply_code";
|
|
1067
|
+
}
|
|
1068
|
+
if (item["codeSystem"] !== undefined) {
|
|
1069
|
+
const item_codeSystem = item["codeSystem"];
|
|
1070
|
+
if (typeof item_codeSystem !== "string" ||
|
|
1071
|
+
!["HCPCS", "NDC", "OTHER"].includes(item_codeSystem))
|
|
1072
|
+
return "clinical_supply_code_system";
|
|
1073
|
+
}
|
|
1074
|
+
if (item["name"] !== undefined) {
|
|
1075
|
+
const item_name = item["name"];
|
|
1076
|
+
if (typeof item_name !== "string" ||
|
|
1077
|
+
item_name.length < 1 ||
|
|
1078
|
+
item_name.length > 240)
|
|
1079
|
+
return "clinical_supply_name";
|
|
1080
|
+
}
|
|
1081
|
+
if (item["quantity"] !== undefined) {
|
|
1082
|
+
const item_quantity = item["quantity"];
|
|
1083
|
+
if (typeof item_quantity !== "number" ||
|
|
1084
|
+
Number.isNaN(item_quantity) ||
|
|
1085
|
+
!Number.isInteger(item_quantity) ||
|
|
1086
|
+
item_quantity < 0 ||
|
|
1087
|
+
item_quantity > 999999)
|
|
1088
|
+
return "clinical_supply_quantity";
|
|
1089
|
+
}
|
|
1090
|
+
if (item["unitOfMeasure"] !== undefined) {
|
|
1091
|
+
const item_unitOfMeasure = item["unitOfMeasure"];
|
|
1092
|
+
if (typeof item_unitOfMeasure !== "string" ||
|
|
1093
|
+
item_unitOfMeasure.length < 1 ||
|
|
1094
|
+
item_unitOfMeasure.length > 20)
|
|
1095
|
+
return "clinical_supply_unit_of_measure";
|
|
1096
|
+
}
|
|
1097
|
+
if (item["supplyDate"] !== undefined) {
|
|
1098
|
+
const item_supplyDate = item["supplyDate"];
|
|
1099
|
+
if (typeof item_supplyDate !== "string" ||
|
|
1100
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_supplyDate) ||
|
|
1101
|
+
!isIsoDate(item_supplyDate))
|
|
1102
|
+
return "clinical_supply_date";
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (value["timeUnits"] !== undefined) {
|
|
1107
|
+
const value_timeUnits = value["timeUnits"];
|
|
1108
|
+
if (!Array.isArray(value_timeUnits) || value_timeUnits.length > 200)
|
|
1109
|
+
return "clinical_time_units";
|
|
1110
|
+
for (const item of value_timeUnits) {
|
|
1111
|
+
if (!isRecord(item))
|
|
1112
|
+
return "clinical_time_unit";
|
|
1113
|
+
if (!["timeId", "date", "durationMinutes"].every((key) => key in item))
|
|
1114
|
+
return "clinical_time_unit_keys";
|
|
1115
|
+
if (!Object.keys(item).every((key) => [
|
|
1116
|
+
"timeId",
|
|
1117
|
+
"date",
|
|
1118
|
+
"durationMinutes",
|
|
1119
|
+
"activityCode",
|
|
1120
|
+
"activityDescription",
|
|
1121
|
+
"clinicianRole",
|
|
1122
|
+
"placeOfService",
|
|
1123
|
+
].includes(key)))
|
|
1124
|
+
return "clinical_time_unit_keys";
|
|
1125
|
+
const item_timeId = item["timeId"];
|
|
1126
|
+
if (typeof item_timeId !== "string" ||
|
|
1127
|
+
item_timeId.length < 1 ||
|
|
1128
|
+
item_timeId.length > 60)
|
|
1129
|
+
return "clinical_time_unit_id";
|
|
1130
|
+
const item_date = item["date"];
|
|
1131
|
+
if (typeof item_date !== "string" ||
|
|
1132
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_date) ||
|
|
1133
|
+
!isIsoDate(item_date))
|
|
1134
|
+
return "clinical_time_unit_date";
|
|
1135
|
+
const item_durationMinutes = item["durationMinutes"];
|
|
1136
|
+
if (typeof item_durationMinutes !== "number" ||
|
|
1137
|
+
Number.isNaN(item_durationMinutes) ||
|
|
1138
|
+
!Number.isInteger(item_durationMinutes) ||
|
|
1139
|
+
item_durationMinutes < 1 ||
|
|
1140
|
+
item_durationMinutes > 1440)
|
|
1141
|
+
return "clinical_time_unit_duration";
|
|
1142
|
+
if (item["activityCode"] !== undefined) {
|
|
1143
|
+
const item_activityCode = item["activityCode"];
|
|
1144
|
+
if (typeof item_activityCode !== "string" ||
|
|
1145
|
+
item_activityCode.length < 1 ||
|
|
1146
|
+
item_activityCode.length > 80)
|
|
1147
|
+
return "clinical_time_unit_activity_code";
|
|
1148
|
+
}
|
|
1149
|
+
if (item["activityDescription"] !== undefined) {
|
|
1150
|
+
const item_activityDescription = item["activityDescription"];
|
|
1151
|
+
if (typeof item_activityDescription !== "string" ||
|
|
1152
|
+
item_activityDescription.length < 1 ||
|
|
1153
|
+
item_activityDescription.length > 240)
|
|
1154
|
+
return "clinical_time_unit_activity_description";
|
|
1155
|
+
}
|
|
1156
|
+
if (item["clinicianRole"] !== undefined) {
|
|
1157
|
+
const item_clinicianRole = item["clinicianRole"];
|
|
1158
|
+
if (typeof item_clinicianRole !== "string" ||
|
|
1159
|
+
![
|
|
1160
|
+
"attending",
|
|
1161
|
+
"physician",
|
|
1162
|
+
"nurse_practitioner",
|
|
1163
|
+
"physician_assistant",
|
|
1164
|
+
"resident",
|
|
1165
|
+
"other",
|
|
1166
|
+
].includes(item_clinicianRole))
|
|
1167
|
+
return "clinical_time_unit_clinician_role";
|
|
1168
|
+
}
|
|
1169
|
+
if (item["placeOfService"] !== undefined) {
|
|
1170
|
+
const item_placeOfService = item["placeOfService"];
|
|
1171
|
+
if (typeof item_placeOfService !== "string" ||
|
|
1172
|
+
!new RegExp("^[0-9]{2}$").test(item_placeOfService))
|
|
1173
|
+
return "clinical_time_unit_place_of_service";
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
if (value["notes"] !== undefined) {
|
|
1178
|
+
const value_notes = value["notes"];
|
|
1179
|
+
if (!Array.isArray(value_notes) || value_notes.length > 50)
|
|
1180
|
+
return "clinical_notes";
|
|
1181
|
+
for (const item of value_notes) {
|
|
1182
|
+
if (!isRecord(item))
|
|
1183
|
+
return "clinical_note";
|
|
1184
|
+
if (!["noteId", "noteType", "note"].every((key) => key in item))
|
|
1185
|
+
return "clinical_note_keys";
|
|
1186
|
+
if (!Object.keys(item).every((key) => ["noteId", "noteType", "note"].includes(key)))
|
|
1187
|
+
return "clinical_note_keys";
|
|
1188
|
+
const item_noteId = item["noteId"];
|
|
1189
|
+
if (typeof item_noteId !== "string" ||
|
|
1190
|
+
item_noteId.length < 1 ||
|
|
1191
|
+
item_noteId.length > 60)
|
|
1192
|
+
return "clinical_note_id";
|
|
1193
|
+
const item_noteType = item["noteType"];
|
|
1194
|
+
if (typeof item_noteType !== "string" ||
|
|
1195
|
+
![
|
|
1196
|
+
"clinical_narrative",
|
|
1197
|
+
"procedure_narrative",
|
|
1198
|
+
"authorization",
|
|
1199
|
+
"correspondence",
|
|
1200
|
+
"other",
|
|
1201
|
+
].includes(item_noteType))
|
|
1202
|
+
return "clinical_note_type";
|
|
1203
|
+
const item_note = item["note"];
|
|
1204
|
+
if (typeof item_note !== "string" ||
|
|
1205
|
+
item_note.length < 1 ||
|
|
1206
|
+
item_note.length > 10000 ||
|
|
1207
|
+
item_note.trim().length === 0)
|
|
1208
|
+
return "clinical_note_text";
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (value["sourceReferences"] !== undefined) {
|
|
1212
|
+
const value_sourceReferences = value["sourceReferences"];
|
|
1213
|
+
if (!Array.isArray(value_sourceReferences) ||
|
|
1214
|
+
value_sourceReferences.length > 50)
|
|
1215
|
+
return "clinical_source_references";
|
|
1216
|
+
for (const item of value_sourceReferences) {
|
|
1217
|
+
if (!isRecord(item))
|
|
1218
|
+
return "clinical_source_reference";
|
|
1219
|
+
if (!["sourceId", "sourceLabel"].every((key) => key in item))
|
|
1220
|
+
return "clinical_source_reference_keys";
|
|
1221
|
+
if (!Object.keys(item).every((key) => [
|
|
1222
|
+
"sourceId",
|
|
1223
|
+
"sourceLabel",
|
|
1224
|
+
"documentId",
|
|
1225
|
+
"excerpt",
|
|
1226
|
+
"sourceVersion",
|
|
1227
|
+
"corpusScope",
|
|
1228
|
+
"publisher",
|
|
1229
|
+
"effectiveDate",
|
|
1230
|
+
"retrievalDate",
|
|
1231
|
+
"coveredPayerProgram",
|
|
1232
|
+
"sourceUrl",
|
|
1233
|
+
"documentHash",
|
|
1234
|
+
"capturedAt",
|
|
1235
|
+
"humanReviewRequired",
|
|
1236
|
+
].includes(key)))
|
|
1237
|
+
return "clinical_source_reference_keys";
|
|
1238
|
+
const item_sourceId = item["sourceId"];
|
|
1239
|
+
if (typeof item_sourceId !== "string" ||
|
|
1240
|
+
item_sourceId.length < 1 ||
|
|
1241
|
+
item_sourceId.length > 60)
|
|
1242
|
+
return "clinical_source_reference_id";
|
|
1243
|
+
const item_sourceLabel = item["sourceLabel"];
|
|
1244
|
+
if (typeof item_sourceLabel !== "string" ||
|
|
1245
|
+
item_sourceLabel.length < 1 ||
|
|
1246
|
+
item_sourceLabel.length > 120)
|
|
1247
|
+
return "clinical_source_reference_label";
|
|
1248
|
+
if (item["documentId"] !== undefined) {
|
|
1249
|
+
const item_documentId = item["documentId"];
|
|
1250
|
+
if (typeof item_documentId !== "string" ||
|
|
1251
|
+
item_documentId.length < 1 ||
|
|
1252
|
+
item_documentId.length > 240)
|
|
1253
|
+
return "clinical_source_reference_document_id";
|
|
1254
|
+
}
|
|
1255
|
+
if (item["excerpt"] !== undefined) {
|
|
1256
|
+
const item_excerpt = item["excerpt"];
|
|
1257
|
+
if (typeof item_excerpt !== "string" ||
|
|
1258
|
+
item_excerpt.length < 1 ||
|
|
1259
|
+
item_excerpt.length > 2000 ||
|
|
1260
|
+
item_excerpt.trim().length === 0)
|
|
1261
|
+
return "clinical_source_reference_excerpt";
|
|
1262
|
+
}
|
|
1263
|
+
if (item["sourceVersion"] !== undefined) {
|
|
1264
|
+
const item_sourceVersion = item["sourceVersion"];
|
|
1265
|
+
if (typeof item_sourceVersion !== "string" ||
|
|
1266
|
+
item_sourceVersion.length < 1 ||
|
|
1267
|
+
item_sourceVersion.length > 80)
|
|
1268
|
+
return "clinical_source_reference_version";
|
|
1269
|
+
}
|
|
1270
|
+
if (item["corpusScope"] !== undefined) {
|
|
1271
|
+
const item_corpusScope = item["corpusScope"];
|
|
1272
|
+
if (typeof item_corpusScope !== "string" ||
|
|
1273
|
+
!["base", "tenant"].includes(item_corpusScope))
|
|
1274
|
+
return "clinical_source_reference_corpus_scope";
|
|
1275
|
+
}
|
|
1276
|
+
if (item["publisher"] !== undefined) {
|
|
1277
|
+
const item_publisher = item["publisher"];
|
|
1278
|
+
if (typeof item_publisher !== "string" ||
|
|
1279
|
+
item_publisher.length < 1 ||
|
|
1280
|
+
item_publisher.length > 240)
|
|
1281
|
+
return "clinical_source_reference_publisher";
|
|
1282
|
+
}
|
|
1283
|
+
if (item["effectiveDate"] !== undefined) {
|
|
1284
|
+
const item_effectiveDate = item["effectiveDate"];
|
|
1285
|
+
if (typeof item_effectiveDate !== "string" ||
|
|
1286
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_effectiveDate) ||
|
|
1287
|
+
!isIsoDate(item_effectiveDate))
|
|
1288
|
+
return "clinical_source_reference_effective_date";
|
|
1289
|
+
}
|
|
1290
|
+
if (item["retrievalDate"] !== undefined) {
|
|
1291
|
+
const item_retrievalDate = item["retrievalDate"];
|
|
1292
|
+
if (typeof item_retrievalDate !== "string" ||
|
|
1293
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_retrievalDate) ||
|
|
1294
|
+
!isIsoDate(item_retrievalDate))
|
|
1295
|
+
return "clinical_source_reference_retrieval_date";
|
|
1296
|
+
}
|
|
1297
|
+
if (item["coveredPayerProgram"] !== undefined) {
|
|
1298
|
+
const item_coveredPayerProgram = item["coveredPayerProgram"];
|
|
1299
|
+
if (typeof item_coveredPayerProgram !== "string" ||
|
|
1300
|
+
item_coveredPayerProgram.length < 1 ||
|
|
1301
|
+
item_coveredPayerProgram.length > 240)
|
|
1302
|
+
return "clinical_source_reference_covered_payer_program";
|
|
1303
|
+
}
|
|
1304
|
+
if (item["sourceUrl"] !== undefined) {
|
|
1305
|
+
const item_sourceUrl = item["sourceUrl"];
|
|
1306
|
+
if (typeof item_sourceUrl !== "string" ||
|
|
1307
|
+
item_sourceUrl.length < 1 ||
|
|
1308
|
+
item_sourceUrl.length > 2048)
|
|
1309
|
+
return "clinical_source_reference_url";
|
|
1310
|
+
}
|
|
1311
|
+
if (item["documentHash"] !== undefined) {
|
|
1312
|
+
const item_documentHash = item["documentHash"];
|
|
1313
|
+
if (typeof item_documentHash !== "string" ||
|
|
1314
|
+
item_documentHash.length < 1 ||
|
|
1315
|
+
item_documentHash.length > 64)
|
|
1316
|
+
return "clinical_source_reference_hash";
|
|
1317
|
+
}
|
|
1318
|
+
if (item["capturedAt"] !== undefined) {
|
|
1319
|
+
const item_capturedAt = item["capturedAt"];
|
|
1320
|
+
if (typeof item_capturedAt !== "string" ||
|
|
1321
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(item_capturedAt) ||
|
|
1322
|
+
!isIsoDate(item_capturedAt))
|
|
1323
|
+
return "clinical_source_reference_captured_at";
|
|
1324
|
+
}
|
|
1325
|
+
if (item["humanReviewRequired"] !== undefined) {
|
|
1326
|
+
const item_humanReviewRequired = item["humanReviewRequired"];
|
|
1327
|
+
if (typeof item_humanReviewRequired !== "boolean" ||
|
|
1328
|
+
item_humanReviewRequired !== true)
|
|
1329
|
+
return "clinical_source_reference_human_review_required";
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1335
|
+
export const validCodingCaseClinical = (value) => codingCaseClinicalValidationError(value) === null;
|
|
1336
|
+
export const CodingCaseClinicalSchemaJson = {
|
|
1337
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1338
|
+
$id: "https://nexalink.care/contracts/coding-case-clinical.schema.json",
|
|
1339
|
+
title: "CodingCaseClinical",
|
|
1340
|
+
description: "Structured clinical and operational facts: diagnoses, procedures, medications, supplies, time entries, notes, and source references. Time entries keep duration and activity structured so workflows such as monthly multi-activity time aggregation never depend on free text for calculations.",
|
|
1341
|
+
version: "1.0.0",
|
|
1342
|
+
type: "object",
|
|
1343
|
+
additionalProperties: false,
|
|
1344
|
+
properties: {
|
|
1345
|
+
diagnoses: {
|
|
1346
|
+
type: "array",
|
|
1347
|
+
maxItems: 100,
|
|
1348
|
+
items: {
|
|
1349
|
+
type: "object",
|
|
1350
|
+
additionalProperties: false,
|
|
1351
|
+
required: ["diagnosisId"],
|
|
1352
|
+
properties: {
|
|
1353
|
+
diagnosisId: {
|
|
1354
|
+
type: "string",
|
|
1355
|
+
minLength: 1,
|
|
1356
|
+
maxLength: 60,
|
|
1357
|
+
},
|
|
1358
|
+
code: {
|
|
1359
|
+
type: "string",
|
|
1360
|
+
minLength: 1,
|
|
1361
|
+
maxLength: 32,
|
|
1362
|
+
},
|
|
1363
|
+
codeSystem: {
|
|
1364
|
+
type: "string",
|
|
1365
|
+
enum: ["ICD-10-CM", "ICD-9-CM", "OTHER"],
|
|
1366
|
+
},
|
|
1367
|
+
codeVersion: {
|
|
1368
|
+
type: "string",
|
|
1369
|
+
minLength: 1,
|
|
1370
|
+
maxLength: 40,
|
|
1371
|
+
},
|
|
1372
|
+
description: {
|
|
1373
|
+
type: "string",
|
|
1374
|
+
minLength: 1,
|
|
1375
|
+
maxLength: 240,
|
|
1376
|
+
},
|
|
1377
|
+
diagnosisType: {
|
|
1378
|
+
type: "string",
|
|
1379
|
+
enum: ["principal", "secondary", "complication", "other"],
|
|
1380
|
+
},
|
|
1381
|
+
onsetDate: {
|
|
1382
|
+
type: "string",
|
|
1383
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1384
|
+
format: "date",
|
|
1385
|
+
},
|
|
1386
|
+
presentOnAdmission: {
|
|
1387
|
+
type: "boolean",
|
|
1388
|
+
},
|
|
1389
|
+
},
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
procedures: {
|
|
1393
|
+
type: "array",
|
|
1394
|
+
maxItems: 100,
|
|
1395
|
+
items: {
|
|
1396
|
+
type: "object",
|
|
1397
|
+
additionalProperties: false,
|
|
1398
|
+
required: ["procedureId"],
|
|
1399
|
+
properties: {
|
|
1400
|
+
procedureId: {
|
|
1401
|
+
type: "string",
|
|
1402
|
+
minLength: 1,
|
|
1403
|
+
maxLength: 60,
|
|
1404
|
+
},
|
|
1405
|
+
code: {
|
|
1406
|
+
type: "string",
|
|
1407
|
+
minLength: 1,
|
|
1408
|
+
maxLength: 64,
|
|
1409
|
+
},
|
|
1410
|
+
codeSystem: {
|
|
1411
|
+
type: "string",
|
|
1412
|
+
enum: ["CPT", "HCPCS", "ICD-10-PCS", "OTHER"],
|
|
1413
|
+
},
|
|
1414
|
+
codeVersion: {
|
|
1415
|
+
type: "string",
|
|
1416
|
+
minLength: 1,
|
|
1417
|
+
maxLength: 40,
|
|
1418
|
+
},
|
|
1419
|
+
description: {
|
|
1420
|
+
type: "string",
|
|
1421
|
+
minLength: 1,
|
|
1422
|
+
maxLength: 240,
|
|
1423
|
+
},
|
|
1424
|
+
performedDate: {
|
|
1425
|
+
type: "string",
|
|
1426
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1427
|
+
format: "date",
|
|
1428
|
+
},
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
},
|
|
1432
|
+
medications: {
|
|
1433
|
+
type: "array",
|
|
1434
|
+
maxItems: 100,
|
|
1435
|
+
items: {
|
|
1436
|
+
type: "object",
|
|
1437
|
+
additionalProperties: false,
|
|
1438
|
+
required: ["medicationId"],
|
|
1439
|
+
properties: {
|
|
1440
|
+
medicationId: {
|
|
1441
|
+
type: "string",
|
|
1442
|
+
minLength: 1,
|
|
1443
|
+
maxLength: 60,
|
|
1444
|
+
},
|
|
1445
|
+
code: {
|
|
1446
|
+
type: "string",
|
|
1447
|
+
minLength: 1,
|
|
1448
|
+
maxLength: 64,
|
|
1449
|
+
},
|
|
1450
|
+
codeSystem: {
|
|
1451
|
+
type: "string",
|
|
1452
|
+
enum: ["NDC", "RxNorm", "OTHER"],
|
|
1453
|
+
},
|
|
1454
|
+
name: {
|
|
1455
|
+
type: "string",
|
|
1456
|
+
minLength: 1,
|
|
1457
|
+
maxLength: 240,
|
|
1458
|
+
},
|
|
1459
|
+
dosage: {
|
|
1460
|
+
type: "string",
|
|
1461
|
+
minLength: 1,
|
|
1462
|
+
maxLength: 120,
|
|
1463
|
+
},
|
|
1464
|
+
route: {
|
|
1465
|
+
type: "string",
|
|
1466
|
+
minLength: 1,
|
|
1467
|
+
maxLength: 80,
|
|
1468
|
+
},
|
|
1469
|
+
administrationDate: {
|
|
1470
|
+
type: "string",
|
|
1471
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1472
|
+
format: "date",
|
|
1473
|
+
},
|
|
1474
|
+
},
|
|
1475
|
+
},
|
|
1476
|
+
},
|
|
1477
|
+
supplies: {
|
|
1478
|
+
type: "array",
|
|
1479
|
+
maxItems: 100,
|
|
1480
|
+
items: {
|
|
1481
|
+
type: "object",
|
|
1482
|
+
additionalProperties: false,
|
|
1483
|
+
required: ["supplyId"],
|
|
1484
|
+
properties: {
|
|
1485
|
+
supplyId: {
|
|
1486
|
+
type: "string",
|
|
1487
|
+
minLength: 1,
|
|
1488
|
+
maxLength: 60,
|
|
1489
|
+
},
|
|
1490
|
+
code: {
|
|
1491
|
+
type: "string",
|
|
1492
|
+
minLength: 1,
|
|
1493
|
+
maxLength: 64,
|
|
1494
|
+
},
|
|
1495
|
+
codeSystem: {
|
|
1496
|
+
type: "string",
|
|
1497
|
+
enum: ["HCPCS", "NDC", "OTHER"],
|
|
1498
|
+
},
|
|
1499
|
+
name: {
|
|
1500
|
+
type: "string",
|
|
1501
|
+
minLength: 1,
|
|
1502
|
+
maxLength: 240,
|
|
1503
|
+
},
|
|
1504
|
+
quantity: {
|
|
1505
|
+
type: "integer",
|
|
1506
|
+
minimum: 0,
|
|
1507
|
+
maximum: 999999,
|
|
1508
|
+
},
|
|
1509
|
+
unitOfMeasure: {
|
|
1510
|
+
type: "string",
|
|
1511
|
+
minLength: 1,
|
|
1512
|
+
maxLength: 20,
|
|
1513
|
+
},
|
|
1514
|
+
supplyDate: {
|
|
1515
|
+
type: "string",
|
|
1516
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1517
|
+
format: "date",
|
|
1518
|
+
},
|
|
1519
|
+
},
|
|
1520
|
+
},
|
|
1521
|
+
},
|
|
1522
|
+
timeUnits: {
|
|
1523
|
+
type: "array",
|
|
1524
|
+
maxItems: 200,
|
|
1525
|
+
items: {
|
|
1526
|
+
type: "object",
|
|
1527
|
+
additionalProperties: false,
|
|
1528
|
+
required: ["timeId", "date", "durationMinutes"],
|
|
1529
|
+
properties: {
|
|
1530
|
+
timeId: {
|
|
1531
|
+
type: "string",
|
|
1532
|
+
minLength: 1,
|
|
1533
|
+
maxLength: 60,
|
|
1534
|
+
},
|
|
1535
|
+
date: {
|
|
1536
|
+
type: "string",
|
|
1537
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1538
|
+
format: "date",
|
|
1539
|
+
},
|
|
1540
|
+
durationMinutes: {
|
|
1541
|
+
type: "integer",
|
|
1542
|
+
minimum: 1,
|
|
1543
|
+
maximum: 1440,
|
|
1544
|
+
},
|
|
1545
|
+
activityCode: {
|
|
1546
|
+
type: "string",
|
|
1547
|
+
minLength: 1,
|
|
1548
|
+
maxLength: 80,
|
|
1549
|
+
},
|
|
1550
|
+
activityDescription: {
|
|
1551
|
+
type: "string",
|
|
1552
|
+
minLength: 1,
|
|
1553
|
+
maxLength: 240,
|
|
1554
|
+
},
|
|
1555
|
+
clinicianRole: {
|
|
1556
|
+
type: "string",
|
|
1557
|
+
enum: [
|
|
1558
|
+
"attending",
|
|
1559
|
+
"physician",
|
|
1560
|
+
"nurse_practitioner",
|
|
1561
|
+
"physician_assistant",
|
|
1562
|
+
"resident",
|
|
1563
|
+
"other",
|
|
1564
|
+
],
|
|
1565
|
+
},
|
|
1566
|
+
placeOfService: {
|
|
1567
|
+
type: "string",
|
|
1568
|
+
pattern: "^[0-9]{2}$",
|
|
1569
|
+
},
|
|
1570
|
+
},
|
|
1571
|
+
},
|
|
1572
|
+
},
|
|
1573
|
+
notes: {
|
|
1574
|
+
type: "array",
|
|
1575
|
+
maxItems: 50,
|
|
1576
|
+
items: {
|
|
1577
|
+
type: "object",
|
|
1578
|
+
additionalProperties: false,
|
|
1579
|
+
required: ["noteId", "noteType", "note"],
|
|
1580
|
+
properties: {
|
|
1581
|
+
noteId: {
|
|
1582
|
+
type: "string",
|
|
1583
|
+
minLength: 1,
|
|
1584
|
+
maxLength: 60,
|
|
1585
|
+
},
|
|
1586
|
+
noteType: {
|
|
1587
|
+
type: "string",
|
|
1588
|
+
enum: [
|
|
1589
|
+
"clinical_narrative",
|
|
1590
|
+
"procedure_narrative",
|
|
1591
|
+
"authorization",
|
|
1592
|
+
"correspondence",
|
|
1593
|
+
"other",
|
|
1594
|
+
],
|
|
1595
|
+
},
|
|
1596
|
+
note: {
|
|
1597
|
+
type: "string",
|
|
1598
|
+
minLength: 1,
|
|
1599
|
+
maxLength: 10000,
|
|
1600
|
+
},
|
|
1601
|
+
},
|
|
1602
|
+
},
|
|
1603
|
+
},
|
|
1604
|
+
sourceReferences: {
|
|
1605
|
+
type: "array",
|
|
1606
|
+
maxItems: 50,
|
|
1607
|
+
items: {
|
|
1608
|
+
type: "object",
|
|
1609
|
+
additionalProperties: false,
|
|
1610
|
+
required: ["sourceId", "sourceLabel"],
|
|
1611
|
+
properties: {
|
|
1612
|
+
sourceId: {
|
|
1613
|
+
type: "string",
|
|
1614
|
+
minLength: 1,
|
|
1615
|
+
maxLength: 60,
|
|
1616
|
+
},
|
|
1617
|
+
sourceLabel: {
|
|
1618
|
+
type: "string",
|
|
1619
|
+
minLength: 1,
|
|
1620
|
+
maxLength: 120,
|
|
1621
|
+
},
|
|
1622
|
+
documentId: {
|
|
1623
|
+
type: "string",
|
|
1624
|
+
minLength: 1,
|
|
1625
|
+
maxLength: 240,
|
|
1626
|
+
},
|
|
1627
|
+
excerpt: {
|
|
1628
|
+
type: "string",
|
|
1629
|
+
minLength: 1,
|
|
1630
|
+
maxLength: 2000,
|
|
1631
|
+
},
|
|
1632
|
+
sourceVersion: {
|
|
1633
|
+
type: "string",
|
|
1634
|
+
minLength: 1,
|
|
1635
|
+
maxLength: 80,
|
|
1636
|
+
},
|
|
1637
|
+
corpusScope: {
|
|
1638
|
+
type: "string",
|
|
1639
|
+
enum: ["base", "tenant"],
|
|
1640
|
+
},
|
|
1641
|
+
publisher: {
|
|
1642
|
+
type: "string",
|
|
1643
|
+
minLength: 1,
|
|
1644
|
+
maxLength: 240,
|
|
1645
|
+
},
|
|
1646
|
+
effectiveDate: {
|
|
1647
|
+
type: "string",
|
|
1648
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1649
|
+
format: "date",
|
|
1650
|
+
},
|
|
1651
|
+
retrievalDate: {
|
|
1652
|
+
type: "string",
|
|
1653
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1654
|
+
format: "date",
|
|
1655
|
+
},
|
|
1656
|
+
coveredPayerProgram: {
|
|
1657
|
+
type: "string",
|
|
1658
|
+
minLength: 1,
|
|
1659
|
+
maxLength: 240,
|
|
1660
|
+
},
|
|
1661
|
+
sourceUrl: {
|
|
1662
|
+
type: "string",
|
|
1663
|
+
minLength: 1,
|
|
1664
|
+
maxLength: 2048,
|
|
1665
|
+
},
|
|
1666
|
+
documentHash: {
|
|
1667
|
+
type: "string",
|
|
1668
|
+
minLength: 1,
|
|
1669
|
+
maxLength: 64,
|
|
1670
|
+
},
|
|
1671
|
+
capturedAt: {
|
|
1672
|
+
type: "string",
|
|
1673
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1674
|
+
format: "date",
|
|
1675
|
+
},
|
|
1676
|
+
humanReviewRequired: {
|
|
1677
|
+
type: "boolean",
|
|
1678
|
+
const: true,
|
|
1679
|
+
},
|
|
1680
|
+
},
|
|
1681
|
+
},
|
|
1682
|
+
},
|
|
1683
|
+
},
|
|
1684
|
+
};
|
|
1685
|
+
// --------------------------------------------------------------------
|
|
1686
|
+
// CodingServiceLine (schema 1.0.0, wire coding-service-line-v1)
|
|
1687
|
+
// --------------------------------------------------------------------
|
|
1688
|
+
export const codingServiceLineSchema = z
|
|
1689
|
+
.object({
|
|
1690
|
+
lineId: z.string().min(1).max(60),
|
|
1691
|
+
submittedCode: z
|
|
1692
|
+
.object({
|
|
1693
|
+
code: z
|
|
1694
|
+
.string()
|
|
1695
|
+
.min(1)
|
|
1696
|
+
.max(64)
|
|
1697
|
+
.refine((value) => value.trim().length > 0),
|
|
1698
|
+
codeSystem: z.enum([
|
|
1699
|
+
"ICD-10-CM",
|
|
1700
|
+
"ICD-10-PCS",
|
|
1701
|
+
"CPT",
|
|
1702
|
+
"HCPCS",
|
|
1703
|
+
"NDC",
|
|
1704
|
+
"CDT",
|
|
1705
|
+
"OTHER",
|
|
1706
|
+
]),
|
|
1707
|
+
codeVersion: z.string().min(1).max(40).optional(),
|
|
1708
|
+
})
|
|
1709
|
+
.strict(),
|
|
1710
|
+
modifiers: z.array(z.string().min(1).max(8)).max(8).optional(),
|
|
1711
|
+
units: z
|
|
1712
|
+
.object({
|
|
1713
|
+
count: z.number().int().min(0).max(999999).optional(),
|
|
1714
|
+
unitOfMeasure: z.string().min(1).max(20).optional(),
|
|
1715
|
+
})
|
|
1716
|
+
.strict()
|
|
1717
|
+
.optional(),
|
|
1718
|
+
linkedDiagnoses: z
|
|
1719
|
+
.array(z
|
|
1720
|
+
.object({
|
|
1721
|
+
diagnosisRef: z.string().min(1).max(60),
|
|
1722
|
+
sequence: z.number().int().min(1).max(99).optional(),
|
|
1723
|
+
})
|
|
1724
|
+
.strict())
|
|
1725
|
+
.max(20)
|
|
1726
|
+
.optional(),
|
|
1727
|
+
serviceDate: z
|
|
1728
|
+
.string()
|
|
1729
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
1730
|
+
.refine(isIsoDate)
|
|
1731
|
+
.optional(),
|
|
1732
|
+
})
|
|
1733
|
+
.strict();
|
|
1734
|
+
export function codingServiceLineValidationError(value) {
|
|
1735
|
+
if (!isRecord(value))
|
|
1736
|
+
return "service_line";
|
|
1737
|
+
if (!["lineId", "submittedCode"].every((key) => key in value))
|
|
1738
|
+
return "service_line_keys";
|
|
1739
|
+
if (!Object.keys(value).every((key) => [
|
|
1740
|
+
"lineId",
|
|
1741
|
+
"submittedCode",
|
|
1742
|
+
"modifiers",
|
|
1743
|
+
"units",
|
|
1744
|
+
"linkedDiagnoses",
|
|
1745
|
+
"serviceDate",
|
|
1746
|
+
].includes(key)))
|
|
1747
|
+
return "service_line_keys";
|
|
1748
|
+
const value_lineId = value["lineId"];
|
|
1749
|
+
if (typeof value_lineId !== "string" ||
|
|
1750
|
+
value_lineId.length < 1 ||
|
|
1751
|
+
value_lineId.length > 60)
|
|
1752
|
+
return "service_line_id";
|
|
1753
|
+
const value_submittedCode = value["submittedCode"];
|
|
1754
|
+
if (!isRecord(value_submittedCode))
|
|
1755
|
+
return "service_line_submitted_code";
|
|
1756
|
+
if (!["code", "codeSystem"].every((key) => key in value_submittedCode))
|
|
1757
|
+
return "service_line_submitted_code_keys";
|
|
1758
|
+
if (!Object.keys(value_submittedCode).every((key) => ["code", "codeSystem", "codeVersion"].includes(key)))
|
|
1759
|
+
return "service_line_submitted_code_keys";
|
|
1760
|
+
const value_submittedCode_code = value_submittedCode["code"];
|
|
1761
|
+
if (typeof value_submittedCode_code !== "string" ||
|
|
1762
|
+
value_submittedCode_code.length < 1 ||
|
|
1763
|
+
value_submittedCode_code.length > 64 ||
|
|
1764
|
+
value_submittedCode_code.trim().length === 0)
|
|
1765
|
+
return "service_line_code";
|
|
1766
|
+
const value_submittedCode_codeSystem = value_submittedCode["codeSystem"];
|
|
1767
|
+
if (typeof value_submittedCode_codeSystem !== "string" ||
|
|
1768
|
+
![
|
|
1769
|
+
"ICD-10-CM",
|
|
1770
|
+
"ICD-10-PCS",
|
|
1771
|
+
"CPT",
|
|
1772
|
+
"HCPCS",
|
|
1773
|
+
"NDC",
|
|
1774
|
+
"CDT",
|
|
1775
|
+
"OTHER",
|
|
1776
|
+
].includes(value_submittedCode_codeSystem))
|
|
1777
|
+
return "service_line_code_system";
|
|
1778
|
+
if (value_submittedCode["codeVersion"] !== undefined) {
|
|
1779
|
+
const value_submittedCode_codeVersion = value_submittedCode["codeVersion"];
|
|
1780
|
+
if (typeof value_submittedCode_codeVersion !== "string" ||
|
|
1781
|
+
value_submittedCode_codeVersion.length < 1 ||
|
|
1782
|
+
value_submittedCode_codeVersion.length > 40)
|
|
1783
|
+
return "service_line_code_version";
|
|
1784
|
+
}
|
|
1785
|
+
if (value["modifiers"] !== undefined) {
|
|
1786
|
+
const value_modifiers = value["modifiers"];
|
|
1787
|
+
if (!Array.isArray(value_modifiers) || value_modifiers.length > 8)
|
|
1788
|
+
return "service_line_modifiers";
|
|
1789
|
+
for (const item of value_modifiers) {
|
|
1790
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 8)
|
|
1791
|
+
return "service_line_modifiers";
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
if (value["units"] !== undefined) {
|
|
1795
|
+
const value_units = value["units"];
|
|
1796
|
+
if (!isRecord(value_units))
|
|
1797
|
+
return "service_line_units";
|
|
1798
|
+
if (!Object.keys(value_units).every((key) => ["count", "unitOfMeasure"].includes(key)))
|
|
1799
|
+
return "service_line_units_keys";
|
|
1800
|
+
if (value_units["count"] !== undefined) {
|
|
1801
|
+
const value_units_count = value_units["count"];
|
|
1802
|
+
if (typeof value_units_count !== "number" ||
|
|
1803
|
+
Number.isNaN(value_units_count) ||
|
|
1804
|
+
!Number.isInteger(value_units_count) ||
|
|
1805
|
+
value_units_count < 0 ||
|
|
1806
|
+
value_units_count > 999999)
|
|
1807
|
+
return "service_line_units_count";
|
|
1808
|
+
}
|
|
1809
|
+
if (value_units["unitOfMeasure"] !== undefined) {
|
|
1810
|
+
const value_units_unitOfMeasure = value_units["unitOfMeasure"];
|
|
1811
|
+
if (typeof value_units_unitOfMeasure !== "string" ||
|
|
1812
|
+
value_units_unitOfMeasure.length < 1 ||
|
|
1813
|
+
value_units_unitOfMeasure.length > 20)
|
|
1814
|
+
return "service_line_units_measure";
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
if (value["linkedDiagnoses"] !== undefined) {
|
|
1818
|
+
const value_linkedDiagnoses = value["linkedDiagnoses"];
|
|
1819
|
+
if (!Array.isArray(value_linkedDiagnoses) ||
|
|
1820
|
+
value_linkedDiagnoses.length > 20)
|
|
1821
|
+
return "service_line_linked_diagnoses";
|
|
1822
|
+
for (const item of value_linkedDiagnoses) {
|
|
1823
|
+
if (!isRecord(item))
|
|
1824
|
+
return "service_line_linked_diagnosis";
|
|
1825
|
+
if (!["diagnosisRef"].every((key) => key in item))
|
|
1826
|
+
return "service_line_linked_diagnosis_keys";
|
|
1827
|
+
if (!Object.keys(item).every((key) => ["diagnosisRef", "sequence"].includes(key)))
|
|
1828
|
+
return "service_line_linked_diagnosis_keys";
|
|
1829
|
+
const item_diagnosisRef = item["diagnosisRef"];
|
|
1830
|
+
if (typeof item_diagnosisRef !== "string" ||
|
|
1831
|
+
item_diagnosisRef.length < 1 ||
|
|
1832
|
+
item_diagnosisRef.length > 60)
|
|
1833
|
+
return "service_line_diagnosis_ref";
|
|
1834
|
+
if (item["sequence"] !== undefined) {
|
|
1835
|
+
const item_sequence = item["sequence"];
|
|
1836
|
+
if (typeof item_sequence !== "number" ||
|
|
1837
|
+
Number.isNaN(item_sequence) ||
|
|
1838
|
+
!Number.isInteger(item_sequence) ||
|
|
1839
|
+
item_sequence < 1 ||
|
|
1840
|
+
item_sequence > 99)
|
|
1841
|
+
return "service_line_diagnosis_sequence";
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
if (value["serviceDate"] !== undefined) {
|
|
1846
|
+
const value_serviceDate = value["serviceDate"];
|
|
1847
|
+
if (typeof value_serviceDate !== "string" ||
|
|
1848
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_serviceDate) ||
|
|
1849
|
+
!isIsoDate(value_serviceDate))
|
|
1850
|
+
return "service_line_service_date";
|
|
1851
|
+
}
|
|
1852
|
+
return null;
|
|
1853
|
+
}
|
|
1854
|
+
export const validCodingServiceLine = (value) => codingServiceLineValidationError(value) === null;
|
|
1855
|
+
export const CodingServiceLineSchemaJson = {
|
|
1856
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1857
|
+
$id: "https://nexalink.care/contracts/coding-service-line.schema.json",
|
|
1858
|
+
title: "CodingServiceLine",
|
|
1859
|
+
description: "One existing (submitted) claim line on a CodingCase. Decisions reference these lines by lineId; the line action is chosen by the decision, never stored here.",
|
|
1860
|
+
version: "1.0.0",
|
|
1861
|
+
type: "object",
|
|
1862
|
+
additionalProperties: false,
|
|
1863
|
+
required: ["lineId", "submittedCode"],
|
|
1864
|
+
properties: {
|
|
1865
|
+
lineId: {
|
|
1866
|
+
type: "string",
|
|
1867
|
+
minLength: 1,
|
|
1868
|
+
maxLength: 60,
|
|
1869
|
+
},
|
|
1870
|
+
submittedCode: {
|
|
1871
|
+
type: "object",
|
|
1872
|
+
additionalProperties: false,
|
|
1873
|
+
required: ["code", "codeSystem"],
|
|
1874
|
+
properties: {
|
|
1875
|
+
code: {
|
|
1876
|
+
type: "string",
|
|
1877
|
+
minLength: 1,
|
|
1878
|
+
maxLength: 64,
|
|
1879
|
+
},
|
|
1880
|
+
codeSystem: {
|
|
1881
|
+
type: "string",
|
|
1882
|
+
enum: [
|
|
1883
|
+
"ICD-10-CM",
|
|
1884
|
+
"ICD-10-PCS",
|
|
1885
|
+
"CPT",
|
|
1886
|
+
"HCPCS",
|
|
1887
|
+
"NDC",
|
|
1888
|
+
"CDT",
|
|
1889
|
+
"OTHER",
|
|
1890
|
+
],
|
|
1891
|
+
},
|
|
1892
|
+
codeVersion: {
|
|
1893
|
+
type: "string",
|
|
1894
|
+
minLength: 1,
|
|
1895
|
+
maxLength: 40,
|
|
1896
|
+
},
|
|
1897
|
+
},
|
|
1898
|
+
},
|
|
1899
|
+
modifiers: {
|
|
1900
|
+
type: "array",
|
|
1901
|
+
maxItems: 8,
|
|
1902
|
+
items: {
|
|
1903
|
+
type: "string",
|
|
1904
|
+
minLength: 1,
|
|
1905
|
+
maxLength: 8,
|
|
1906
|
+
},
|
|
1907
|
+
},
|
|
1908
|
+
units: {
|
|
1909
|
+
type: "object",
|
|
1910
|
+
additionalProperties: false,
|
|
1911
|
+
properties: {
|
|
1912
|
+
count: {
|
|
1913
|
+
type: "integer",
|
|
1914
|
+
minimum: 0,
|
|
1915
|
+
maximum: 999999,
|
|
1916
|
+
},
|
|
1917
|
+
unitOfMeasure: {
|
|
1918
|
+
type: "string",
|
|
1919
|
+
minLength: 1,
|
|
1920
|
+
maxLength: 20,
|
|
1921
|
+
},
|
|
1922
|
+
},
|
|
1923
|
+
},
|
|
1924
|
+
linkedDiagnoses: {
|
|
1925
|
+
type: "array",
|
|
1926
|
+
maxItems: 20,
|
|
1927
|
+
items: {
|
|
1928
|
+
type: "object",
|
|
1929
|
+
additionalProperties: false,
|
|
1930
|
+
required: ["diagnosisRef"],
|
|
1931
|
+
properties: {
|
|
1932
|
+
diagnosisRef: {
|
|
1933
|
+
type: "string",
|
|
1934
|
+
minLength: 1,
|
|
1935
|
+
maxLength: 60,
|
|
1936
|
+
},
|
|
1937
|
+
sequence: {
|
|
1938
|
+
type: "integer",
|
|
1939
|
+
minimum: 1,
|
|
1940
|
+
maximum: 99,
|
|
1941
|
+
},
|
|
1942
|
+
},
|
|
1943
|
+
},
|
|
1944
|
+
},
|
|
1945
|
+
serviceDate: {
|
|
1946
|
+
type: "string",
|
|
1947
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1948
|
+
format: "date",
|
|
1949
|
+
},
|
|
1950
|
+
},
|
|
1951
|
+
};
|
|
1952
|
+
// --------------------------------------------------------------------
|
|
1953
|
+
// CodingExtension (schema 1.0.0, wire coding-extension-v1)
|
|
1954
|
+
// --------------------------------------------------------------------
|
|
1955
|
+
export const codingExtensionSchema = z
|
|
1956
|
+
.object({
|
|
1957
|
+
namespace: z
|
|
1958
|
+
.string()
|
|
1959
|
+
.regex(new RegExp("^[a-z0-9]+([._-][a-z0-9]+)*$"))
|
|
1960
|
+
.min(3)
|
|
1961
|
+
.max(160),
|
|
1962
|
+
schemaVersion: z.string().min(1).max(40),
|
|
1963
|
+
payload: z
|
|
1964
|
+
.object({})
|
|
1965
|
+
.passthrough()
|
|
1966
|
+
.refine((value) => Object.keys(value).length <= 50),
|
|
1967
|
+
})
|
|
1968
|
+
.strict();
|
|
1969
|
+
export function codingExtensionValidationError(value) {
|
|
1970
|
+
if (!isRecord(value))
|
|
1971
|
+
return "extension";
|
|
1972
|
+
if (!["namespace", "schemaVersion", "payload"].every((key) => key in value))
|
|
1973
|
+
return "extension_keys";
|
|
1974
|
+
if (!Object.keys(value).every((key) => ["namespace", "schemaVersion", "payload"].includes(key)))
|
|
1975
|
+
return "extension_keys";
|
|
1976
|
+
const value_namespace = value["namespace"];
|
|
1977
|
+
if (typeof value_namespace !== "string" ||
|
|
1978
|
+
value_namespace.length < 3 ||
|
|
1979
|
+
value_namespace.length > 160 ||
|
|
1980
|
+
!new RegExp("^[a-z0-9]+([._-][a-z0-9]+)*$").test(value_namespace))
|
|
1981
|
+
return "extension_namespace";
|
|
1982
|
+
const value_schemaVersion = value["schemaVersion"];
|
|
1983
|
+
if (typeof value_schemaVersion !== "string" ||
|
|
1984
|
+
value_schemaVersion.length < 1 ||
|
|
1985
|
+
value_schemaVersion.length > 40)
|
|
1986
|
+
return "extension_schema_version";
|
|
1987
|
+
const value_payload = value["payload"];
|
|
1988
|
+
if (!isRecord(value_payload))
|
|
1989
|
+
return "extension_payload";
|
|
1990
|
+
if (Object.keys(value_payload).length > 50)
|
|
1991
|
+
return "extension_payload";
|
|
1992
|
+
return null;
|
|
1993
|
+
}
|
|
1994
|
+
export const validCodingExtension = (value) => codingExtensionValidationError(value) === null;
|
|
1995
|
+
export const CodingExtensionSchemaJson = {
|
|
1996
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1997
|
+
$id: "https://nexalink.care/contracts/coding-extension.schema.json",
|
|
1998
|
+
title: "CodingExtension",
|
|
1999
|
+
description: "A namespaced, bounded extension attached to a CodingCase or CodingDecision. Extensions carry pack-specific data without turning the shared envelope into an unbounded bag of specialty fields. Namespace ownership follows reverse-domain convention; Nexalink reserves com.nexalink and org.nexalink.",
|
|
2000
|
+
version: "1.0.0",
|
|
2001
|
+
type: "object",
|
|
2002
|
+
additionalProperties: false,
|
|
2003
|
+
required: ["namespace", "schemaVersion", "payload"],
|
|
2004
|
+
properties: {
|
|
2005
|
+
namespace: {
|
|
2006
|
+
type: "string",
|
|
2007
|
+
pattern: "^[a-z0-9]+([._-][a-z0-9]+)*$",
|
|
2008
|
+
minLength: 3,
|
|
2009
|
+
maxLength: 160,
|
|
2010
|
+
},
|
|
2011
|
+
schemaVersion: {
|
|
2012
|
+
type: "string",
|
|
2013
|
+
minLength: 1,
|
|
2014
|
+
maxLength: 40,
|
|
2015
|
+
},
|
|
2016
|
+
payload: {
|
|
2017
|
+
type: "object",
|
|
2018
|
+
maxProperties: 50,
|
|
2019
|
+
properties: {},
|
|
2020
|
+
},
|
|
2021
|
+
},
|
|
2022
|
+
};
|
|
2023
|
+
// --------------------------------------------------------------------
|
|
2024
|
+
// CodingCase (schema 1.0.0, wire coding-case-v1)
|
|
2025
|
+
// --------------------------------------------------------------------
|
|
2026
|
+
export const codingCaseSchema = z
|
|
2027
|
+
.object({
|
|
2028
|
+
caseId: z.string().min(1).max(128),
|
|
2029
|
+
analyticsId: z.string().min(1).max(128).optional(),
|
|
2030
|
+
tenantReference: z.string().min(1).max(128).optional(),
|
|
2031
|
+
codingIntent: z.enum([
|
|
2032
|
+
"encounter_review",
|
|
2033
|
+
"claim_review",
|
|
2034
|
+
"longitudinal_review",
|
|
2035
|
+
"monthly_time_aggregation",
|
|
2036
|
+
"batch_review",
|
|
2037
|
+
]),
|
|
2038
|
+
servicePeriod: z
|
|
2039
|
+
.object({
|
|
2040
|
+
startDate: z
|
|
2041
|
+
.string()
|
|
2042
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
2043
|
+
.refine(isIsoDate),
|
|
2044
|
+
endDate: z
|
|
2045
|
+
.string()
|
|
2046
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
2047
|
+
.refine(isIsoDate)
|
|
2048
|
+
.optional(),
|
|
2049
|
+
})
|
|
2050
|
+
.strict(),
|
|
2051
|
+
context: codingCaseContextSchema,
|
|
2052
|
+
payer: codingCasePayerSchema.optional(),
|
|
2053
|
+
clinical: codingCaseClinicalSchema,
|
|
2054
|
+
submittedClaimLines: z.array(codingServiceLineSchema).max(100).optional(),
|
|
2055
|
+
extensions: z.array(codingExtensionSchema).max(25).optional(),
|
|
2056
|
+
})
|
|
2057
|
+
.strict();
|
|
2058
|
+
export function codingCaseValidationError(value) {
|
|
2059
|
+
if (!isRecord(value))
|
|
2060
|
+
return "coding_case";
|
|
2061
|
+
if (!["caseId", "codingIntent", "servicePeriod", "context", "clinical"].every((key) => key in value))
|
|
2062
|
+
return "coding_case_keys";
|
|
2063
|
+
if (!Object.keys(value).every((key) => [
|
|
2064
|
+
"caseId",
|
|
2065
|
+
"analyticsId",
|
|
2066
|
+
"tenantReference",
|
|
2067
|
+
"codingIntent",
|
|
2068
|
+
"servicePeriod",
|
|
2069
|
+
"context",
|
|
2070
|
+
"payer",
|
|
2071
|
+
"clinical",
|
|
2072
|
+
"submittedClaimLines",
|
|
2073
|
+
"extensions",
|
|
2074
|
+
].includes(key)))
|
|
2075
|
+
return "coding_case_keys";
|
|
2076
|
+
const value_caseId = value["caseId"];
|
|
2077
|
+
if (typeof value_caseId !== "string" ||
|
|
2078
|
+
value_caseId.length < 1 ||
|
|
2079
|
+
value_caseId.length > 128)
|
|
2080
|
+
return "case_id";
|
|
2081
|
+
if (value["analyticsId"] !== undefined) {
|
|
2082
|
+
const value_analyticsId = value["analyticsId"];
|
|
2083
|
+
if (typeof value_analyticsId !== "string" ||
|
|
2084
|
+
value_analyticsId.length < 1 ||
|
|
2085
|
+
value_analyticsId.length > 128)
|
|
2086
|
+
return "case_analytics_id";
|
|
2087
|
+
}
|
|
2088
|
+
if (value["tenantReference"] !== undefined) {
|
|
2089
|
+
const value_tenantReference = value["tenantReference"];
|
|
2090
|
+
if (typeof value_tenantReference !== "string" ||
|
|
2091
|
+
value_tenantReference.length < 1 ||
|
|
2092
|
+
value_tenantReference.length > 128)
|
|
2093
|
+
return "case_tenant_reference";
|
|
2094
|
+
}
|
|
2095
|
+
const value_codingIntent = value["codingIntent"];
|
|
2096
|
+
if (typeof value_codingIntent !== "string" ||
|
|
2097
|
+
![
|
|
2098
|
+
"encounter_review",
|
|
2099
|
+
"claim_review",
|
|
2100
|
+
"longitudinal_review",
|
|
2101
|
+
"monthly_time_aggregation",
|
|
2102
|
+
"batch_review",
|
|
2103
|
+
].includes(value_codingIntent))
|
|
2104
|
+
return "case_coding_intent";
|
|
2105
|
+
const value_servicePeriod = value["servicePeriod"];
|
|
2106
|
+
if (!isRecord(value_servicePeriod))
|
|
2107
|
+
return "case_service_period";
|
|
2108
|
+
if (!["startDate"].every((key) => key in value_servicePeriod))
|
|
2109
|
+
return "case_service_period_keys";
|
|
2110
|
+
if (!Object.keys(value_servicePeriod).every((key) => ["startDate", "endDate"].includes(key)))
|
|
2111
|
+
return "case_service_period_keys";
|
|
2112
|
+
const value_servicePeriod_startDate = value_servicePeriod["startDate"];
|
|
2113
|
+
if (typeof value_servicePeriod_startDate !== "string" ||
|
|
2114
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_servicePeriod_startDate) ||
|
|
2115
|
+
!isIsoDate(value_servicePeriod_startDate))
|
|
2116
|
+
return "case_service_period_start";
|
|
2117
|
+
if (value_servicePeriod["endDate"] !== undefined) {
|
|
2118
|
+
const value_servicePeriod_endDate = value_servicePeriod["endDate"];
|
|
2119
|
+
if (typeof value_servicePeriod_endDate !== "string" ||
|
|
2120
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_servicePeriod_endDate) ||
|
|
2121
|
+
!isIsoDate(value_servicePeriod_endDate))
|
|
2122
|
+
return "case_service_period_end";
|
|
2123
|
+
}
|
|
2124
|
+
const value_context = value["context"];
|
|
2125
|
+
const value_contextRefError = codingCaseContextValidationError(value_context);
|
|
2126
|
+
if (value_contextRefError !== null)
|
|
2127
|
+
return value_contextRefError;
|
|
2128
|
+
if (value["payer"] !== undefined) {
|
|
2129
|
+
const value_payer = value["payer"];
|
|
2130
|
+
const value_payerRefError = codingCasePayerValidationError(value_payer);
|
|
2131
|
+
if (value_payerRefError !== null)
|
|
2132
|
+
return value_payerRefError;
|
|
2133
|
+
}
|
|
2134
|
+
const value_clinical = value["clinical"];
|
|
2135
|
+
const value_clinicalRefError = codingCaseClinicalValidationError(value_clinical);
|
|
2136
|
+
if (value_clinicalRefError !== null)
|
|
2137
|
+
return value_clinicalRefError;
|
|
2138
|
+
if (value["submittedClaimLines"] !== undefined) {
|
|
2139
|
+
const value_submittedClaimLines = value["submittedClaimLines"];
|
|
2140
|
+
if (!Array.isArray(value_submittedClaimLines) ||
|
|
2141
|
+
value_submittedClaimLines.length > 100)
|
|
2142
|
+
return "case_submitted_claim_lines";
|
|
2143
|
+
for (const item of value_submittedClaimLines) {
|
|
2144
|
+
const itemRefError = codingServiceLineValidationError(item);
|
|
2145
|
+
if (itemRefError !== null)
|
|
2146
|
+
return itemRefError;
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
if (value["extensions"] !== undefined) {
|
|
2150
|
+
const value_extensions = value["extensions"];
|
|
2151
|
+
if (!Array.isArray(value_extensions) || value_extensions.length > 25)
|
|
2152
|
+
return "case_extensions";
|
|
2153
|
+
for (const item of value_extensions) {
|
|
2154
|
+
const itemRefError = codingExtensionValidationError(item);
|
|
2155
|
+
if (itemRefError !== null)
|
|
2156
|
+
return itemRefError;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
return null;
|
|
2160
|
+
}
|
|
2161
|
+
export const validCodingCase = (value) => codingCaseValidationError(value) === null;
|
|
2162
|
+
export const CodingCaseSchemaJson = {
|
|
2163
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2164
|
+
$id: "https://nexalink.care/contracts/coding-case.schema.json",
|
|
2165
|
+
title: "CodingCase",
|
|
2166
|
+
description: "The canonical case envelope for encounter, claim-review, longitudinal, monthly time aggregation, and batch coding workflows. caseId is a client-supplied direct reference; analyticsId is the separate analytics-safe identifier that may be referenced by decisions and metrics without exposing case identity.",
|
|
2167
|
+
version: "1.0.0",
|
|
2168
|
+
type: "object",
|
|
2169
|
+
additionalProperties: false,
|
|
2170
|
+
required: ["caseId", "codingIntent", "servicePeriod", "context", "clinical"],
|
|
2171
|
+
properties: {
|
|
2172
|
+
caseId: {
|
|
2173
|
+
type: "string",
|
|
2174
|
+
minLength: 1,
|
|
2175
|
+
maxLength: 128,
|
|
2176
|
+
},
|
|
2177
|
+
analyticsId: {
|
|
2178
|
+
type: "string",
|
|
2179
|
+
minLength: 1,
|
|
2180
|
+
maxLength: 128,
|
|
2181
|
+
},
|
|
2182
|
+
tenantReference: {
|
|
2183
|
+
type: "string",
|
|
2184
|
+
minLength: 1,
|
|
2185
|
+
maxLength: 128,
|
|
2186
|
+
},
|
|
2187
|
+
codingIntent: {
|
|
2188
|
+
type: "string",
|
|
2189
|
+
enum: [
|
|
2190
|
+
"encounter_review",
|
|
2191
|
+
"claim_review",
|
|
2192
|
+
"longitudinal_review",
|
|
2193
|
+
"monthly_time_aggregation",
|
|
2194
|
+
"batch_review",
|
|
2195
|
+
],
|
|
2196
|
+
},
|
|
2197
|
+
servicePeriod: {
|
|
2198
|
+
type: "object",
|
|
2199
|
+
additionalProperties: false,
|
|
2200
|
+
required: ["startDate"],
|
|
2201
|
+
properties: {
|
|
2202
|
+
startDate: {
|
|
2203
|
+
type: "string",
|
|
2204
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
2205
|
+
format: "date",
|
|
2206
|
+
},
|
|
2207
|
+
endDate: {
|
|
2208
|
+
type: "string",
|
|
2209
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
2210
|
+
format: "date",
|
|
2211
|
+
},
|
|
2212
|
+
},
|
|
2213
|
+
},
|
|
2214
|
+
context: {
|
|
2215
|
+
$ref: "coding-case-context.schema.json",
|
|
2216
|
+
},
|
|
2217
|
+
payer: {
|
|
2218
|
+
$ref: "coding-case-payer.schema.json",
|
|
2219
|
+
},
|
|
2220
|
+
clinical: {
|
|
2221
|
+
$ref: "coding-case-clinical.schema.json",
|
|
2222
|
+
},
|
|
2223
|
+
submittedClaimLines: {
|
|
2224
|
+
type: "array",
|
|
2225
|
+
maxItems: 100,
|
|
2226
|
+
items: {
|
|
2227
|
+
$ref: "coding-service-line.schema.json",
|
|
2228
|
+
},
|
|
2229
|
+
},
|
|
2230
|
+
extensions: {
|
|
2231
|
+
type: "array",
|
|
2232
|
+
maxItems: 25,
|
|
2233
|
+
items: {
|
|
2234
|
+
$ref: "coding-extension.schema.json",
|
|
2235
|
+
},
|
|
2236
|
+
},
|
|
2237
|
+
},
|
|
2238
|
+
};
|
|
2239
|
+
// --------------------------------------------------------------------
|
|
2240
|
+
// CodingBatch (schema 1.0.0, wire coding-batch-v1)
|
|
2241
|
+
// --------------------------------------------------------------------
|
|
2242
|
+
export const codingBatchSchema = z
|
|
2243
|
+
.object({
|
|
2244
|
+
batchId: z.string().min(1).max(128),
|
|
2245
|
+
tenantReference: z.string().min(1).max(128).optional(),
|
|
2246
|
+
intent: z.literal("batch_review"),
|
|
2247
|
+
cases: z.array(codingCaseSchema).min(1).max(100),
|
|
2248
|
+
createdBy: z.string().min(1).max(128).optional(),
|
|
2249
|
+
createdAt: z
|
|
2250
|
+
.string()
|
|
2251
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$"))
|
|
2252
|
+
.refine(isRfc3339DateTime)
|
|
2253
|
+
.max(64),
|
|
2254
|
+
extensions: z.array(codingExtensionSchema).max(25).optional(),
|
|
2255
|
+
})
|
|
2256
|
+
.strict();
|
|
2257
|
+
export function codingBatchValidationError(value) {
|
|
2258
|
+
if (!isRecord(value))
|
|
2259
|
+
return "coding_batch";
|
|
2260
|
+
if (!["batchId", "intent", "cases", "createdAt"].every((key) => key in value))
|
|
2261
|
+
return "coding_batch_keys";
|
|
2262
|
+
if (!Object.keys(value).every((key) => [
|
|
2263
|
+
"batchId",
|
|
2264
|
+
"tenantReference",
|
|
2265
|
+
"intent",
|
|
2266
|
+
"cases",
|
|
2267
|
+
"createdBy",
|
|
2268
|
+
"createdAt",
|
|
2269
|
+
"extensions",
|
|
2270
|
+
].includes(key)))
|
|
2271
|
+
return "coding_batch_keys";
|
|
2272
|
+
const value_batchId = value["batchId"];
|
|
2273
|
+
if (typeof value_batchId !== "string" ||
|
|
2274
|
+
value_batchId.length < 1 ||
|
|
2275
|
+
value_batchId.length > 128)
|
|
2276
|
+
return "batch_id";
|
|
2277
|
+
if (value["tenantReference"] !== undefined) {
|
|
2278
|
+
const value_tenantReference = value["tenantReference"];
|
|
2279
|
+
if (typeof value_tenantReference !== "string" ||
|
|
2280
|
+
value_tenantReference.length < 1 ||
|
|
2281
|
+
value_tenantReference.length > 128)
|
|
2282
|
+
return "batch_tenant_reference";
|
|
2283
|
+
}
|
|
2284
|
+
const value_intent = value["intent"];
|
|
2285
|
+
if (typeof value_intent !== "string" || value_intent !== "batch_review")
|
|
2286
|
+
return "batch_intent";
|
|
2287
|
+
const value_cases = value["cases"];
|
|
2288
|
+
if (!Array.isArray(value_cases) ||
|
|
2289
|
+
value_cases.length < 1 ||
|
|
2290
|
+
value_cases.length > 100)
|
|
2291
|
+
return "batch_cases";
|
|
2292
|
+
for (const item of value_cases) {
|
|
2293
|
+
const itemRefError = codingCaseValidationError(item);
|
|
2294
|
+
if (itemRefError !== null)
|
|
2295
|
+
return itemRefError;
|
|
2296
|
+
}
|
|
2297
|
+
if (value["createdBy"] !== undefined) {
|
|
2298
|
+
const value_createdBy = value["createdBy"];
|
|
2299
|
+
if (typeof value_createdBy !== "string" ||
|
|
2300
|
+
value_createdBy.length < 1 ||
|
|
2301
|
+
value_createdBy.length > 128)
|
|
2302
|
+
return "batch_created_by";
|
|
2303
|
+
}
|
|
2304
|
+
const value_createdAt = value["createdAt"];
|
|
2305
|
+
if (typeof value_createdAt !== "string" ||
|
|
2306
|
+
value_createdAt.length > 64 ||
|
|
2307
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$").test(value_createdAt) ||
|
|
2308
|
+
!isRfc3339DateTime(value_createdAt))
|
|
2309
|
+
return "batch_created_at";
|
|
2310
|
+
if (value["extensions"] !== undefined) {
|
|
2311
|
+
const value_extensions = value["extensions"];
|
|
2312
|
+
if (!Array.isArray(value_extensions) || value_extensions.length > 25)
|
|
2313
|
+
return "batch_extensions";
|
|
2314
|
+
for (const item of value_extensions) {
|
|
2315
|
+
const itemRefError = codingExtensionValidationError(item);
|
|
2316
|
+
if (itemRefError !== null)
|
|
2317
|
+
return itemRefError;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
return null;
|
|
2321
|
+
}
|
|
2322
|
+
export const validCodingBatch = (value) => codingBatchValidationError(value) === null;
|
|
2323
|
+
export const CodingBatchSchemaJson = {
|
|
2324
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2325
|
+
$id: "https://nexalink.care/contracts/coding-batch.schema.json",
|
|
2326
|
+
title: "CodingBatch",
|
|
2327
|
+
description: "A bounded batch envelope carrying CodingCase instances for batch review. Batch size is capped so one execution remains within runtime limits; unbounded or streaming workloads are out of scope for this envelope.",
|
|
2328
|
+
version: "1.0.0",
|
|
2329
|
+
type: "object",
|
|
2330
|
+
additionalProperties: false,
|
|
2331
|
+
required: ["batchId", "intent", "cases", "createdAt"],
|
|
2332
|
+
properties: {
|
|
2333
|
+
batchId: {
|
|
2334
|
+
type: "string",
|
|
2335
|
+
minLength: 1,
|
|
2336
|
+
maxLength: 128,
|
|
2337
|
+
},
|
|
2338
|
+
tenantReference: {
|
|
2339
|
+
type: "string",
|
|
2340
|
+
minLength: 1,
|
|
2341
|
+
maxLength: 128,
|
|
2342
|
+
},
|
|
2343
|
+
intent: {
|
|
2344
|
+
type: "string",
|
|
2345
|
+
const: "batch_review",
|
|
2346
|
+
},
|
|
2347
|
+
cases: {
|
|
2348
|
+
type: "array",
|
|
2349
|
+
minItems: 1,
|
|
2350
|
+
maxItems: 100,
|
|
2351
|
+
items: {
|
|
2352
|
+
$ref: "coding-case.schema.json",
|
|
2353
|
+
},
|
|
2354
|
+
},
|
|
2355
|
+
createdBy: {
|
|
2356
|
+
type: "string",
|
|
2357
|
+
minLength: 1,
|
|
2358
|
+
maxLength: 128,
|
|
2359
|
+
},
|
|
2360
|
+
createdAt: {
|
|
2361
|
+
type: "string",
|
|
2362
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$",
|
|
2363
|
+
format: "date-time",
|
|
2364
|
+
maxLength: 64,
|
|
2365
|
+
},
|
|
2366
|
+
extensions: {
|
|
2367
|
+
type: "array",
|
|
2368
|
+
maxItems: 25,
|
|
2369
|
+
items: {
|
|
2370
|
+
$ref: "coding-extension.schema.json",
|
|
2371
|
+
},
|
|
2372
|
+
},
|
|
2373
|
+
},
|
|
2374
|
+
};
|
|
2375
|
+
// --------------------------------------------------------------------
|
|
2376
|
+
// CodingDecisionLine (schema 1.0.0, wire coding-decision-line-v1)
|
|
2377
|
+
// --------------------------------------------------------------------
|
|
2378
|
+
export const codingDecisionLineSchema = z
|
|
2379
|
+
.object({
|
|
2380
|
+
lineId: z.string().min(1).max(60),
|
|
2381
|
+
action: z.enum(["add", "retain", "replace", "remove", "review"]),
|
|
2382
|
+
code: z
|
|
2383
|
+
.object({
|
|
2384
|
+
code: z
|
|
2385
|
+
.string()
|
|
2386
|
+
.min(1)
|
|
2387
|
+
.max(64)
|
|
2388
|
+
.refine((value) => value.trim().length > 0),
|
|
2389
|
+
codeSystem: z.enum([
|
|
2390
|
+
"ICD-10-CM",
|
|
2391
|
+
"ICD-10-PCS",
|
|
2392
|
+
"CPT",
|
|
2393
|
+
"HCPCS",
|
|
2394
|
+
"NDC",
|
|
2395
|
+
"CDT",
|
|
2396
|
+
"REVENUE_CODE",
|
|
2397
|
+
"DRG",
|
|
2398
|
+
"OTHER",
|
|
2399
|
+
]),
|
|
2400
|
+
codeVersion: z.string().min(1).max(40).optional(),
|
|
2401
|
+
})
|
|
2402
|
+
.strict(),
|
|
2403
|
+
modifiers: z.array(z.string().min(1).max(8)).max(8).optional(),
|
|
2404
|
+
units: z
|
|
2405
|
+
.object({
|
|
2406
|
+
count: z.number().int().min(0).max(999999).optional(),
|
|
2407
|
+
unitOfMeasure: z.string().min(1).max(20).optional(),
|
|
2408
|
+
})
|
|
2409
|
+
.strict()
|
|
2410
|
+
.optional(),
|
|
2411
|
+
linkedDiagnoses: z
|
|
2412
|
+
.array(z
|
|
2413
|
+
.object({
|
|
2414
|
+
diagnosisRef: z.string().min(1).max(60),
|
|
2415
|
+
sequence: z.number().int().min(1).max(99).optional(),
|
|
2416
|
+
})
|
|
2417
|
+
.strict())
|
|
2418
|
+
.max(20)
|
|
2419
|
+
.optional(),
|
|
2420
|
+
sequence: z.number().int().min(1).max(999).optional(),
|
|
2421
|
+
confidence: z.enum(["low", "medium", "high"]),
|
|
2422
|
+
rationale: z
|
|
2423
|
+
.string()
|
|
2424
|
+
.min(1)
|
|
2425
|
+
.max(2000)
|
|
2426
|
+
.refine((value) => value.trim().length > 0),
|
|
2427
|
+
evidenceRefs: z.array(z.string().min(1).max(64)).max(10).optional(),
|
|
2428
|
+
gapRefs: z.array(z.string().min(1).max(64)).max(10).optional(),
|
|
2429
|
+
conflictRefs: z.array(z.string().min(1).max(64)).max(10).optional(),
|
|
2430
|
+
})
|
|
2431
|
+
.strict();
|
|
2432
|
+
export function codingDecisionLineValidationError(value) {
|
|
2433
|
+
if (!isRecord(value))
|
|
2434
|
+
return "decision_line";
|
|
2435
|
+
if (!["lineId", "action", "code", "confidence", "rationale"].every((key) => key in value))
|
|
2436
|
+
return "decision_line_keys";
|
|
2437
|
+
if (!Object.keys(value).every((key) => [
|
|
2438
|
+
"lineId",
|
|
2439
|
+
"action",
|
|
2440
|
+
"code",
|
|
2441
|
+
"modifiers",
|
|
2442
|
+
"units",
|
|
2443
|
+
"linkedDiagnoses",
|
|
2444
|
+
"sequence",
|
|
2445
|
+
"confidence",
|
|
2446
|
+
"rationale",
|
|
2447
|
+
"evidenceRefs",
|
|
2448
|
+
"gapRefs",
|
|
2449
|
+
"conflictRefs",
|
|
2450
|
+
].includes(key)))
|
|
2451
|
+
return "decision_line_keys";
|
|
2452
|
+
const value_lineId = value["lineId"];
|
|
2453
|
+
if (typeof value_lineId !== "string" ||
|
|
2454
|
+
value_lineId.length < 1 ||
|
|
2455
|
+
value_lineId.length > 60)
|
|
2456
|
+
return "decision_line_id";
|
|
2457
|
+
const value_action = value["action"];
|
|
2458
|
+
if (typeof value_action !== "string" ||
|
|
2459
|
+
!["add", "retain", "replace", "remove", "review"].includes(value_action))
|
|
2460
|
+
return "decision_line_action";
|
|
2461
|
+
const value_code = value["code"];
|
|
2462
|
+
if (!isRecord(value_code))
|
|
2463
|
+
return "decision_line_code";
|
|
2464
|
+
if (!["code", "codeSystem"].every((key) => key in value_code))
|
|
2465
|
+
return "decision_line_code_keys";
|
|
2466
|
+
if (!Object.keys(value_code).every((key) => ["code", "codeSystem", "codeVersion"].includes(key)))
|
|
2467
|
+
return "decision_line_code_keys";
|
|
2468
|
+
const value_code_code = value_code["code"];
|
|
2469
|
+
if (typeof value_code_code !== "string" ||
|
|
2470
|
+
value_code_code.length < 1 ||
|
|
2471
|
+
value_code_code.length > 64 ||
|
|
2472
|
+
value_code_code.trim().length === 0)
|
|
2473
|
+
return "decision_line_code_value";
|
|
2474
|
+
const value_code_codeSystem = value_code["codeSystem"];
|
|
2475
|
+
if (typeof value_code_codeSystem !== "string" ||
|
|
2476
|
+
![
|
|
2477
|
+
"ICD-10-CM",
|
|
2478
|
+
"ICD-10-PCS",
|
|
2479
|
+
"CPT",
|
|
2480
|
+
"HCPCS",
|
|
2481
|
+
"NDC",
|
|
2482
|
+
"CDT",
|
|
2483
|
+
"REVENUE_CODE",
|
|
2484
|
+
"DRG",
|
|
2485
|
+
"OTHER",
|
|
2486
|
+
].includes(value_code_codeSystem))
|
|
2487
|
+
return "decision_line_code_system";
|
|
2488
|
+
if (value_code["codeVersion"] !== undefined) {
|
|
2489
|
+
const value_code_codeVersion = value_code["codeVersion"];
|
|
2490
|
+
if (typeof value_code_codeVersion !== "string" ||
|
|
2491
|
+
value_code_codeVersion.length < 1 ||
|
|
2492
|
+
value_code_codeVersion.length > 40)
|
|
2493
|
+
return "decision_line_code_version";
|
|
2494
|
+
}
|
|
2495
|
+
if (value["modifiers"] !== undefined) {
|
|
2496
|
+
const value_modifiers = value["modifiers"];
|
|
2497
|
+
if (!Array.isArray(value_modifiers) || value_modifiers.length > 8)
|
|
2498
|
+
return "decision_line_modifiers";
|
|
2499
|
+
for (const item of value_modifiers) {
|
|
2500
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 8)
|
|
2501
|
+
return "decision_line_modifiers";
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
if (value["units"] !== undefined) {
|
|
2505
|
+
const value_units = value["units"];
|
|
2506
|
+
if (!isRecord(value_units))
|
|
2507
|
+
return "decision_line_units";
|
|
2508
|
+
if (!Object.keys(value_units).every((key) => ["count", "unitOfMeasure"].includes(key)))
|
|
2509
|
+
return "decision_line_units_keys";
|
|
2510
|
+
if (value_units["count"] !== undefined) {
|
|
2511
|
+
const value_units_count = value_units["count"];
|
|
2512
|
+
if (typeof value_units_count !== "number" ||
|
|
2513
|
+
Number.isNaN(value_units_count) ||
|
|
2514
|
+
!Number.isInteger(value_units_count) ||
|
|
2515
|
+
value_units_count < 0 ||
|
|
2516
|
+
value_units_count > 999999)
|
|
2517
|
+
return "decision_line_units_count";
|
|
2518
|
+
}
|
|
2519
|
+
if (value_units["unitOfMeasure"] !== undefined) {
|
|
2520
|
+
const value_units_unitOfMeasure = value_units["unitOfMeasure"];
|
|
2521
|
+
if (typeof value_units_unitOfMeasure !== "string" ||
|
|
2522
|
+
value_units_unitOfMeasure.length < 1 ||
|
|
2523
|
+
value_units_unitOfMeasure.length > 20)
|
|
2524
|
+
return "decision_line_units_measure";
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
if (value["linkedDiagnoses"] !== undefined) {
|
|
2528
|
+
const value_linkedDiagnoses = value["linkedDiagnoses"];
|
|
2529
|
+
if (!Array.isArray(value_linkedDiagnoses) ||
|
|
2530
|
+
value_linkedDiagnoses.length > 20)
|
|
2531
|
+
return "decision_line_linked_diagnoses";
|
|
2532
|
+
for (const item of value_linkedDiagnoses) {
|
|
2533
|
+
if (!isRecord(item))
|
|
2534
|
+
return "decision_line_linked_diagnosis";
|
|
2535
|
+
if (!["diagnosisRef"].every((key) => key in item))
|
|
2536
|
+
return "decision_line_linked_diagnosis_keys";
|
|
2537
|
+
if (!Object.keys(item).every((key) => ["diagnosisRef", "sequence"].includes(key)))
|
|
2538
|
+
return "decision_line_linked_diagnosis_keys";
|
|
2539
|
+
const item_diagnosisRef = item["diagnosisRef"];
|
|
2540
|
+
if (typeof item_diagnosisRef !== "string" ||
|
|
2541
|
+
item_diagnosisRef.length < 1 ||
|
|
2542
|
+
item_diagnosisRef.length > 60)
|
|
2543
|
+
return "decision_line_diagnosis_ref";
|
|
2544
|
+
if (item["sequence"] !== undefined) {
|
|
2545
|
+
const item_sequence = item["sequence"];
|
|
2546
|
+
if (typeof item_sequence !== "number" ||
|
|
2547
|
+
Number.isNaN(item_sequence) ||
|
|
2548
|
+
!Number.isInteger(item_sequence) ||
|
|
2549
|
+
item_sequence < 1 ||
|
|
2550
|
+
item_sequence > 99)
|
|
2551
|
+
return "decision_line_diagnosis_sequence";
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
if (value["sequence"] !== undefined) {
|
|
2556
|
+
const value_sequence = value["sequence"];
|
|
2557
|
+
if (typeof value_sequence !== "number" ||
|
|
2558
|
+
Number.isNaN(value_sequence) ||
|
|
2559
|
+
!Number.isInteger(value_sequence) ||
|
|
2560
|
+
value_sequence < 1 ||
|
|
2561
|
+
value_sequence > 999)
|
|
2562
|
+
return "decision_line_sequence";
|
|
2563
|
+
}
|
|
2564
|
+
const value_confidence = value["confidence"];
|
|
2565
|
+
if (typeof value_confidence !== "string" ||
|
|
2566
|
+
!["low", "medium", "high"].includes(value_confidence))
|
|
2567
|
+
return "decision_line_confidence";
|
|
2568
|
+
const value_rationale = value["rationale"];
|
|
2569
|
+
if (typeof value_rationale !== "string" ||
|
|
2570
|
+
value_rationale.length < 1 ||
|
|
2571
|
+
value_rationale.length > 2000 ||
|
|
2572
|
+
value_rationale.trim().length === 0)
|
|
2573
|
+
return "decision_line_rationale";
|
|
2574
|
+
if (value["evidenceRefs"] !== undefined) {
|
|
2575
|
+
const value_evidenceRefs = value["evidenceRefs"];
|
|
2576
|
+
if (!Array.isArray(value_evidenceRefs) || value_evidenceRefs.length > 10)
|
|
2577
|
+
return "decision_line_evidence_refs";
|
|
2578
|
+
for (const item of value_evidenceRefs) {
|
|
2579
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 64)
|
|
2580
|
+
return "decision_line_evidence_refs";
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
if (value["gapRefs"] !== undefined) {
|
|
2584
|
+
const value_gapRefs = value["gapRefs"];
|
|
2585
|
+
if (!Array.isArray(value_gapRefs) || value_gapRefs.length > 10)
|
|
2586
|
+
return "decision_line_gap_refs";
|
|
2587
|
+
for (const item of value_gapRefs) {
|
|
2588
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 64)
|
|
2589
|
+
return "decision_line_gap_refs";
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
if (value["conflictRefs"] !== undefined) {
|
|
2593
|
+
const value_conflictRefs = value["conflictRefs"];
|
|
2594
|
+
if (!Array.isArray(value_conflictRefs) || value_conflictRefs.length > 10)
|
|
2595
|
+
return "decision_line_conflict_refs";
|
|
2596
|
+
for (const item of value_conflictRefs) {
|
|
2597
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 64)
|
|
2598
|
+
return "decision_line_conflict_refs";
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
return null;
|
|
2602
|
+
}
|
|
2603
|
+
export const validCodingDecisionLine = (value) => codingDecisionLineValidationError(value) === null;
|
|
2604
|
+
export const CodingDecisionLineSchemaJson = {
|
|
2605
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2606
|
+
$id: "https://nexalink.care/contracts/coding-decision-line.schema.json",
|
|
2607
|
+
title: "CodingDecisionLine",
|
|
2608
|
+
description: "One proposed claim-line action within a CodingDecision. Actions are add, retain, replace, remove, or review; each line carries code identity, modifiers, units, linked diagnoses, sequencing, confidence, rationale, and evidence references.",
|
|
2609
|
+
version: "1.0.0",
|
|
2610
|
+
type: "object",
|
|
2611
|
+
additionalProperties: false,
|
|
2612
|
+
required: ["lineId", "action", "code", "confidence", "rationale"],
|
|
2613
|
+
properties: {
|
|
2614
|
+
lineId: {
|
|
2615
|
+
type: "string",
|
|
2616
|
+
minLength: 1,
|
|
2617
|
+
maxLength: 60,
|
|
2618
|
+
},
|
|
2619
|
+
action: {
|
|
2620
|
+
type: "string",
|
|
2621
|
+
enum: ["add", "retain", "replace", "remove", "review"],
|
|
2622
|
+
},
|
|
2623
|
+
code: {
|
|
2624
|
+
type: "object",
|
|
2625
|
+
additionalProperties: false,
|
|
2626
|
+
required: ["code", "codeSystem"],
|
|
2627
|
+
properties: {
|
|
2628
|
+
code: {
|
|
2629
|
+
type: "string",
|
|
2630
|
+
minLength: 1,
|
|
2631
|
+
maxLength: 64,
|
|
2632
|
+
},
|
|
2633
|
+
codeSystem: {
|
|
2634
|
+
type: "string",
|
|
2635
|
+
enum: [
|
|
2636
|
+
"ICD-10-CM",
|
|
2637
|
+
"ICD-10-PCS",
|
|
2638
|
+
"CPT",
|
|
2639
|
+
"HCPCS",
|
|
2640
|
+
"NDC",
|
|
2641
|
+
"CDT",
|
|
2642
|
+
"REVENUE_CODE",
|
|
2643
|
+
"DRG",
|
|
2644
|
+
"OTHER",
|
|
2645
|
+
],
|
|
2646
|
+
},
|
|
2647
|
+
codeVersion: {
|
|
2648
|
+
type: "string",
|
|
2649
|
+
minLength: 1,
|
|
2650
|
+
maxLength: 40,
|
|
2651
|
+
},
|
|
2652
|
+
},
|
|
2653
|
+
},
|
|
2654
|
+
modifiers: {
|
|
2655
|
+
type: "array",
|
|
2656
|
+
maxItems: 8,
|
|
2657
|
+
items: {
|
|
2658
|
+
type: "string",
|
|
2659
|
+
minLength: 1,
|
|
2660
|
+
maxLength: 8,
|
|
2661
|
+
},
|
|
2662
|
+
},
|
|
2663
|
+
units: {
|
|
2664
|
+
type: "object",
|
|
2665
|
+
additionalProperties: false,
|
|
2666
|
+
properties: {
|
|
2667
|
+
count: {
|
|
2668
|
+
type: "integer",
|
|
2669
|
+
minimum: 0,
|
|
2670
|
+
maximum: 999999,
|
|
2671
|
+
},
|
|
2672
|
+
unitOfMeasure: {
|
|
2673
|
+
type: "string",
|
|
2674
|
+
minLength: 1,
|
|
2675
|
+
maxLength: 20,
|
|
2676
|
+
},
|
|
2677
|
+
},
|
|
2678
|
+
},
|
|
2679
|
+
linkedDiagnoses: {
|
|
2680
|
+
type: "array",
|
|
2681
|
+
maxItems: 20,
|
|
2682
|
+
items: {
|
|
2683
|
+
type: "object",
|
|
2684
|
+
additionalProperties: false,
|
|
2685
|
+
required: ["diagnosisRef"],
|
|
2686
|
+
properties: {
|
|
2687
|
+
diagnosisRef: {
|
|
2688
|
+
type: "string",
|
|
2689
|
+
minLength: 1,
|
|
2690
|
+
maxLength: 60,
|
|
2691
|
+
},
|
|
2692
|
+
sequence: {
|
|
2693
|
+
type: "integer",
|
|
2694
|
+
minimum: 1,
|
|
2695
|
+
maximum: 99,
|
|
2696
|
+
},
|
|
2697
|
+
},
|
|
2698
|
+
},
|
|
2699
|
+
},
|
|
2700
|
+
sequence: {
|
|
2701
|
+
type: "integer",
|
|
2702
|
+
minimum: 1,
|
|
2703
|
+
maximum: 999,
|
|
2704
|
+
},
|
|
2705
|
+
confidence: {
|
|
2706
|
+
type: "string",
|
|
2707
|
+
enum: ["low", "medium", "high"],
|
|
2708
|
+
},
|
|
2709
|
+
rationale: {
|
|
2710
|
+
type: "string",
|
|
2711
|
+
minLength: 1,
|
|
2712
|
+
maxLength: 2000,
|
|
2713
|
+
},
|
|
2714
|
+
evidenceRefs: {
|
|
2715
|
+
type: "array",
|
|
2716
|
+
maxItems: 10,
|
|
2717
|
+
items: {
|
|
2718
|
+
type: "string",
|
|
2719
|
+
minLength: 1,
|
|
2720
|
+
maxLength: 64,
|
|
2721
|
+
},
|
|
2722
|
+
},
|
|
2723
|
+
gapRefs: {
|
|
2724
|
+
type: "array",
|
|
2725
|
+
maxItems: 10,
|
|
2726
|
+
items: {
|
|
2727
|
+
type: "string",
|
|
2728
|
+
minLength: 1,
|
|
2729
|
+
maxLength: 64,
|
|
2730
|
+
},
|
|
2731
|
+
},
|
|
2732
|
+
conflictRefs: {
|
|
2733
|
+
type: "array",
|
|
2734
|
+
maxItems: 10,
|
|
2735
|
+
items: {
|
|
2736
|
+
type: "string",
|
|
2737
|
+
minLength: 1,
|
|
2738
|
+
maxLength: 64,
|
|
2739
|
+
},
|
|
2740
|
+
},
|
|
2741
|
+
},
|
|
2742
|
+
};
|
|
2743
|
+
// --------------------------------------------------------------------
|
|
2744
|
+
// CodingEvidence (schema 1.0.0, wire coding-evidence-v1)
|
|
2745
|
+
// --------------------------------------------------------------------
|
|
2746
|
+
export const codingEvidenceSchema = z
|
|
2747
|
+
.object({
|
|
2748
|
+
evidenceId: z.string().min(1).max(64),
|
|
2749
|
+
type: z.enum([
|
|
2750
|
+
"clinical",
|
|
2751
|
+
"coding_guideline",
|
|
2752
|
+
"payer_policy",
|
|
2753
|
+
"plan_policy",
|
|
2754
|
+
"contract_configuration",
|
|
2755
|
+
"terminology_validity",
|
|
2756
|
+
"rule_execution",
|
|
2757
|
+
]),
|
|
2758
|
+
source: z
|
|
2759
|
+
.string()
|
|
2760
|
+
.min(1)
|
|
2761
|
+
.max(240)
|
|
2762
|
+
.refine((value) => value.trim().length > 0),
|
|
2763
|
+
sourceVersion: z.string().min(1).max(80),
|
|
2764
|
+
publisher: z.string().min(1).max(240).optional(),
|
|
2765
|
+
scope: z.enum(["national", "payer", "plan", "contract", "tenant"]),
|
|
2766
|
+
effectiveFrom: z
|
|
2767
|
+
.string()
|
|
2768
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
2769
|
+
.refine(isIsoDate),
|
|
2770
|
+
effectiveTo: z
|
|
2771
|
+
.string()
|
|
2772
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
2773
|
+
.refine(isIsoDate)
|
|
2774
|
+
.optional(),
|
|
2775
|
+
stableId: z.string().min(1).max(240),
|
|
2776
|
+
excerpt: z
|
|
2777
|
+
.string()
|
|
2778
|
+
.min(1)
|
|
2779
|
+
.max(2000)
|
|
2780
|
+
.refine((value) => value.trim().length > 0),
|
|
2781
|
+
retrievedAt: z
|
|
2782
|
+
.string()
|
|
2783
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}$"))
|
|
2784
|
+
.refine(isIsoDate),
|
|
2785
|
+
})
|
|
2786
|
+
.strict();
|
|
2787
|
+
export function codingEvidenceValidationError(value) {
|
|
2788
|
+
if (!isRecord(value))
|
|
2789
|
+
return "evidence";
|
|
2790
|
+
if (![
|
|
2791
|
+
"evidenceId",
|
|
2792
|
+
"type",
|
|
2793
|
+
"source",
|
|
2794
|
+
"sourceVersion",
|
|
2795
|
+
"scope",
|
|
2796
|
+
"effectiveFrom",
|
|
2797
|
+
"stableId",
|
|
2798
|
+
"excerpt",
|
|
2799
|
+
"retrievedAt",
|
|
2800
|
+
].every((key) => key in value))
|
|
2801
|
+
return "evidence_keys";
|
|
2802
|
+
if (!Object.keys(value).every((key) => [
|
|
2803
|
+
"evidenceId",
|
|
2804
|
+
"type",
|
|
2805
|
+
"source",
|
|
2806
|
+
"sourceVersion",
|
|
2807
|
+
"publisher",
|
|
2808
|
+
"scope",
|
|
2809
|
+
"effectiveFrom",
|
|
2810
|
+
"effectiveTo",
|
|
2811
|
+
"stableId",
|
|
2812
|
+
"excerpt",
|
|
2813
|
+
"retrievedAt",
|
|
2814
|
+
].includes(key)))
|
|
2815
|
+
return "evidence_keys";
|
|
2816
|
+
const value_evidenceId = value["evidenceId"];
|
|
2817
|
+
if (typeof value_evidenceId !== "string" ||
|
|
2818
|
+
value_evidenceId.length < 1 ||
|
|
2819
|
+
value_evidenceId.length > 64)
|
|
2820
|
+
return "evidence_id";
|
|
2821
|
+
const value_type = value["type"];
|
|
2822
|
+
if (typeof value_type !== "string" ||
|
|
2823
|
+
![
|
|
2824
|
+
"clinical",
|
|
2825
|
+
"coding_guideline",
|
|
2826
|
+
"payer_policy",
|
|
2827
|
+
"plan_policy",
|
|
2828
|
+
"contract_configuration",
|
|
2829
|
+
"terminology_validity",
|
|
2830
|
+
"rule_execution",
|
|
2831
|
+
].includes(value_type))
|
|
2832
|
+
return "evidence_type";
|
|
2833
|
+
const value_source = value["source"];
|
|
2834
|
+
if (typeof value_source !== "string" ||
|
|
2835
|
+
value_source.length < 1 ||
|
|
2836
|
+
value_source.length > 240 ||
|
|
2837
|
+
value_source.trim().length === 0)
|
|
2838
|
+
return "evidence_source";
|
|
2839
|
+
const value_sourceVersion = value["sourceVersion"];
|
|
2840
|
+
if (typeof value_sourceVersion !== "string" ||
|
|
2841
|
+
value_sourceVersion.length < 1 ||
|
|
2842
|
+
value_sourceVersion.length > 80)
|
|
2843
|
+
return "evidence_source_version";
|
|
2844
|
+
if (value["publisher"] !== undefined) {
|
|
2845
|
+
const value_publisher = value["publisher"];
|
|
2846
|
+
if (typeof value_publisher !== "string" ||
|
|
2847
|
+
value_publisher.length < 1 ||
|
|
2848
|
+
value_publisher.length > 240)
|
|
2849
|
+
return "evidence_publisher";
|
|
2850
|
+
}
|
|
2851
|
+
const value_scope = value["scope"];
|
|
2852
|
+
if (typeof value_scope !== "string" ||
|
|
2853
|
+
!["national", "payer", "plan", "contract", "tenant"].includes(value_scope))
|
|
2854
|
+
return "evidence_scope";
|
|
2855
|
+
const value_effectiveFrom = value["effectiveFrom"];
|
|
2856
|
+
if (typeof value_effectiveFrom !== "string" ||
|
|
2857
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_effectiveFrom) ||
|
|
2858
|
+
!isIsoDate(value_effectiveFrom))
|
|
2859
|
+
return "evidence_effective_from";
|
|
2860
|
+
if (value["effectiveTo"] !== undefined) {
|
|
2861
|
+
const value_effectiveTo = value["effectiveTo"];
|
|
2862
|
+
if (typeof value_effectiveTo !== "string" ||
|
|
2863
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_effectiveTo) ||
|
|
2864
|
+
!isIsoDate(value_effectiveTo))
|
|
2865
|
+
return "evidence_effective_to";
|
|
2866
|
+
}
|
|
2867
|
+
const value_stableId = value["stableId"];
|
|
2868
|
+
if (typeof value_stableId !== "string" ||
|
|
2869
|
+
value_stableId.length < 1 ||
|
|
2870
|
+
value_stableId.length > 240)
|
|
2871
|
+
return "evidence_stable_id";
|
|
2872
|
+
const value_excerpt = value["excerpt"];
|
|
2873
|
+
if (typeof value_excerpt !== "string" ||
|
|
2874
|
+
value_excerpt.length < 1 ||
|
|
2875
|
+
value_excerpt.length > 2000 ||
|
|
2876
|
+
value_excerpt.trim().length === 0)
|
|
2877
|
+
return "evidence_excerpt";
|
|
2878
|
+
const value_retrievedAt = value["retrievedAt"];
|
|
2879
|
+
if (typeof value_retrievedAt !== "string" ||
|
|
2880
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}$").test(value_retrievedAt) ||
|
|
2881
|
+
!isIsoDate(value_retrievedAt))
|
|
2882
|
+
return "evidence_retrieved_at";
|
|
2883
|
+
return null;
|
|
2884
|
+
}
|
|
2885
|
+
export const validCodingEvidence = (value) => codingEvidenceValidationError(value) === null;
|
|
2886
|
+
export const CodingEvidenceSchemaJson = {
|
|
2887
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2888
|
+
$id: "https://nexalink.care/contracts/coding-evidence.schema.json",
|
|
2889
|
+
title: "CodingEvidence",
|
|
2890
|
+
description: "One typed, traced evidence item attached to a decision. Every item carries source, scope, version, effective period, and a stable identifier so reviews can be reconstructed. Licensed terminology content is never distributed through evidence excerpts.",
|
|
2891
|
+
version: "1.0.0",
|
|
2892
|
+
type: "object",
|
|
2893
|
+
additionalProperties: false,
|
|
2894
|
+
required: [
|
|
2895
|
+
"evidenceId",
|
|
2896
|
+
"type",
|
|
2897
|
+
"source",
|
|
2898
|
+
"sourceVersion",
|
|
2899
|
+
"scope",
|
|
2900
|
+
"effectiveFrom",
|
|
2901
|
+
"stableId",
|
|
2902
|
+
"excerpt",
|
|
2903
|
+
"retrievedAt",
|
|
2904
|
+
],
|
|
2905
|
+
properties: {
|
|
2906
|
+
evidenceId: {
|
|
2907
|
+
type: "string",
|
|
2908
|
+
minLength: 1,
|
|
2909
|
+
maxLength: 64,
|
|
2910
|
+
},
|
|
2911
|
+
type: {
|
|
2912
|
+
type: "string",
|
|
2913
|
+
enum: [
|
|
2914
|
+
"clinical",
|
|
2915
|
+
"coding_guideline",
|
|
2916
|
+
"payer_policy",
|
|
2917
|
+
"plan_policy",
|
|
2918
|
+
"contract_configuration",
|
|
2919
|
+
"terminology_validity",
|
|
2920
|
+
"rule_execution",
|
|
2921
|
+
],
|
|
2922
|
+
},
|
|
2923
|
+
source: {
|
|
2924
|
+
type: "string",
|
|
2925
|
+
minLength: 1,
|
|
2926
|
+
maxLength: 240,
|
|
2927
|
+
},
|
|
2928
|
+
sourceVersion: {
|
|
2929
|
+
type: "string",
|
|
2930
|
+
minLength: 1,
|
|
2931
|
+
maxLength: 80,
|
|
2932
|
+
},
|
|
2933
|
+
publisher: {
|
|
2934
|
+
type: "string",
|
|
2935
|
+
minLength: 1,
|
|
2936
|
+
maxLength: 240,
|
|
2937
|
+
},
|
|
2938
|
+
scope: {
|
|
2939
|
+
type: "string",
|
|
2940
|
+
enum: ["national", "payer", "plan", "contract", "tenant"],
|
|
2941
|
+
},
|
|
2942
|
+
effectiveFrom: {
|
|
2943
|
+
type: "string",
|
|
2944
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
2945
|
+
format: "date",
|
|
2946
|
+
},
|
|
2947
|
+
effectiveTo: {
|
|
2948
|
+
type: "string",
|
|
2949
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
2950
|
+
format: "date",
|
|
2951
|
+
},
|
|
2952
|
+
stableId: {
|
|
2953
|
+
type: "string",
|
|
2954
|
+
minLength: 1,
|
|
2955
|
+
maxLength: 240,
|
|
2956
|
+
},
|
|
2957
|
+
excerpt: {
|
|
2958
|
+
type: "string",
|
|
2959
|
+
minLength: 1,
|
|
2960
|
+
maxLength: 2000,
|
|
2961
|
+
},
|
|
2962
|
+
retrievedAt: {
|
|
2963
|
+
type: "string",
|
|
2964
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
2965
|
+
format: "date",
|
|
2966
|
+
},
|
|
2967
|
+
},
|
|
2968
|
+
};
|
|
2969
|
+
// --------------------------------------------------------------------
|
|
2970
|
+
// CodingRuleResult (schema 1.0.0, wire coding-rule-result-v1)
|
|
2971
|
+
// --------------------------------------------------------------------
|
|
2972
|
+
export const codingRuleResultSchema = z
|
|
2973
|
+
.object({
|
|
2974
|
+
ruleId: z.string().min(1).max(120),
|
|
2975
|
+
ruleVersion: z.string().min(1).max(40),
|
|
2976
|
+
outcome: z.enum([
|
|
2977
|
+
"satisfied",
|
|
2978
|
+
"failed",
|
|
2979
|
+
"rejected",
|
|
2980
|
+
"escalated",
|
|
2981
|
+
"conflicted",
|
|
2982
|
+
"warning",
|
|
2983
|
+
]),
|
|
2984
|
+
severity: z.enum(["info", "warning", "blocking"]).optional(),
|
|
2985
|
+
inputs: z
|
|
2986
|
+
.array(z
|
|
2987
|
+
.object({
|
|
2988
|
+
name: z.string().min(1).max(80),
|
|
2989
|
+
value: z.string().min(1).max(2000),
|
|
2990
|
+
})
|
|
2991
|
+
.strict())
|
|
2992
|
+
.max(30)
|
|
2993
|
+
.optional(),
|
|
2994
|
+
reason: z.string().min(1).max(120).optional(),
|
|
2995
|
+
explanation: z
|
|
2996
|
+
.string()
|
|
2997
|
+
.min(1)
|
|
2998
|
+
.max(1000)
|
|
2999
|
+
.refine((value) => value.trim().length > 0)
|
|
3000
|
+
.optional(),
|
|
3001
|
+
evidence: z.string().min(1).max(2000).optional(),
|
|
3002
|
+
})
|
|
3003
|
+
.strict();
|
|
3004
|
+
export function codingRuleResultValidationError(value) {
|
|
3005
|
+
if (!isRecord(value))
|
|
3006
|
+
return "rule_result";
|
|
3007
|
+
if (!["ruleId", "ruleVersion", "outcome"].every((key) => key in value))
|
|
3008
|
+
return "rule_result_keys";
|
|
3009
|
+
if (!Object.keys(value).every((key) => [
|
|
3010
|
+
"ruleId",
|
|
3011
|
+
"ruleVersion",
|
|
3012
|
+
"outcome",
|
|
3013
|
+
"severity",
|
|
3014
|
+
"inputs",
|
|
3015
|
+
"reason",
|
|
3016
|
+
"explanation",
|
|
3017
|
+
"evidence",
|
|
3018
|
+
].includes(key)))
|
|
3019
|
+
return "rule_result_keys";
|
|
3020
|
+
const value_ruleId = value["ruleId"];
|
|
3021
|
+
if (typeof value_ruleId !== "string" ||
|
|
3022
|
+
value_ruleId.length < 1 ||
|
|
3023
|
+
value_ruleId.length > 120)
|
|
3024
|
+
return "rule_result_id";
|
|
3025
|
+
const value_ruleVersion = value["ruleVersion"];
|
|
3026
|
+
if (typeof value_ruleVersion !== "string" ||
|
|
3027
|
+
value_ruleVersion.length < 1 ||
|
|
3028
|
+
value_ruleVersion.length > 40)
|
|
3029
|
+
return "rule_result_version";
|
|
3030
|
+
const value_outcome = value["outcome"];
|
|
3031
|
+
if (typeof value_outcome !== "string" ||
|
|
3032
|
+
![
|
|
3033
|
+
"satisfied",
|
|
3034
|
+
"failed",
|
|
3035
|
+
"rejected",
|
|
3036
|
+
"escalated",
|
|
3037
|
+
"conflicted",
|
|
3038
|
+
"warning",
|
|
3039
|
+
].includes(value_outcome))
|
|
3040
|
+
return "rule_result_outcome";
|
|
3041
|
+
if (value["severity"] !== undefined) {
|
|
3042
|
+
const value_severity = value["severity"];
|
|
3043
|
+
if (typeof value_severity !== "string" ||
|
|
3044
|
+
!["info", "warning", "blocking"].includes(value_severity))
|
|
3045
|
+
return "rule_result_severity";
|
|
3046
|
+
}
|
|
3047
|
+
if (value["inputs"] !== undefined) {
|
|
3048
|
+
const value_inputs = value["inputs"];
|
|
3049
|
+
if (!Array.isArray(value_inputs) || value_inputs.length > 30)
|
|
3050
|
+
return "rule_result_inputs";
|
|
3051
|
+
for (const item of value_inputs) {
|
|
3052
|
+
if (!isRecord(item))
|
|
3053
|
+
return "rule_result_input";
|
|
3054
|
+
if (!["name", "value"].every((key) => key in item))
|
|
3055
|
+
return "rule_result_input_keys";
|
|
3056
|
+
if (!Object.keys(item).every((key) => ["name", "value"].includes(key)))
|
|
3057
|
+
return "rule_result_input_keys";
|
|
3058
|
+
const item_name = item["name"];
|
|
3059
|
+
if (typeof item_name !== "string" ||
|
|
3060
|
+
item_name.length < 1 ||
|
|
3061
|
+
item_name.length > 80)
|
|
3062
|
+
return "rule_result_input_name";
|
|
3063
|
+
const item_value = item["value"];
|
|
3064
|
+
if (typeof item_value !== "string" ||
|
|
3065
|
+
item_value.length < 1 ||
|
|
3066
|
+
item_value.length > 2000)
|
|
3067
|
+
return "rule_result_input_value";
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
if (value["reason"] !== undefined) {
|
|
3071
|
+
const value_reason = value["reason"];
|
|
3072
|
+
if (typeof value_reason !== "string" ||
|
|
3073
|
+
value_reason.length < 1 ||
|
|
3074
|
+
value_reason.length > 120)
|
|
3075
|
+
return "rule_result_reason";
|
|
3076
|
+
}
|
|
3077
|
+
if (value["explanation"] !== undefined) {
|
|
3078
|
+
const value_explanation = value["explanation"];
|
|
3079
|
+
if (typeof value_explanation !== "string" ||
|
|
3080
|
+
value_explanation.length < 1 ||
|
|
3081
|
+
value_explanation.length > 1000 ||
|
|
3082
|
+
value_explanation.trim().length === 0)
|
|
3083
|
+
return "rule_result_explanation";
|
|
3084
|
+
}
|
|
3085
|
+
if (value["evidence"] !== undefined) {
|
|
3086
|
+
const value_evidence = value["evidence"];
|
|
3087
|
+
if (typeof value_evidence !== "string" ||
|
|
3088
|
+
value_evidence.length < 1 ||
|
|
3089
|
+
value_evidence.length > 2000)
|
|
3090
|
+
return "rule_result_evidence";
|
|
3091
|
+
}
|
|
3092
|
+
return null;
|
|
3093
|
+
}
|
|
3094
|
+
export const validCodingRuleResult = (value) => codingRuleResultValidationError(value) === null;
|
|
3095
|
+
export const CodingRuleResultSchemaJson = {
|
|
3096
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
3097
|
+
$id: "https://nexalink.care/contracts/coding-rule-result.schema.json",
|
|
3098
|
+
title: "CodingRuleResult",
|
|
3099
|
+
description: "One deterministic rule execution trace attached to a decision. Rules never rely on the model for validity, bundling, sequencing, modifiers, units, or time calculations; each trace records the rule identity, version, inputs, outcome, and explanation needed to replay the decision.",
|
|
3100
|
+
version: "1.0.0",
|
|
3101
|
+
type: "object",
|
|
3102
|
+
additionalProperties: false,
|
|
3103
|
+
required: ["ruleId", "ruleVersion", "outcome"],
|
|
3104
|
+
properties: {
|
|
3105
|
+
ruleId: {
|
|
3106
|
+
type: "string",
|
|
3107
|
+
minLength: 1,
|
|
3108
|
+
maxLength: 120,
|
|
3109
|
+
},
|
|
3110
|
+
ruleVersion: {
|
|
3111
|
+
type: "string",
|
|
3112
|
+
minLength: 1,
|
|
3113
|
+
maxLength: 40,
|
|
3114
|
+
},
|
|
3115
|
+
outcome: {
|
|
3116
|
+
type: "string",
|
|
3117
|
+
enum: [
|
|
3118
|
+
"satisfied",
|
|
3119
|
+
"failed",
|
|
3120
|
+
"rejected",
|
|
3121
|
+
"escalated",
|
|
3122
|
+
"conflicted",
|
|
3123
|
+
"warning",
|
|
3124
|
+
],
|
|
3125
|
+
},
|
|
3126
|
+
severity: {
|
|
3127
|
+
type: "string",
|
|
3128
|
+
enum: ["info", "warning", "blocking"],
|
|
3129
|
+
},
|
|
3130
|
+
inputs: {
|
|
3131
|
+
type: "array",
|
|
3132
|
+
maxItems: 30,
|
|
3133
|
+
items: {
|
|
3134
|
+
type: "object",
|
|
3135
|
+
additionalProperties: false,
|
|
3136
|
+
required: ["name", "value"],
|
|
3137
|
+
properties: {
|
|
3138
|
+
name: {
|
|
3139
|
+
type: "string",
|
|
3140
|
+
minLength: 1,
|
|
3141
|
+
maxLength: 80,
|
|
3142
|
+
},
|
|
3143
|
+
value: {
|
|
3144
|
+
type: "string",
|
|
3145
|
+
minLength: 1,
|
|
3146
|
+
maxLength: 2000,
|
|
3147
|
+
},
|
|
3148
|
+
},
|
|
3149
|
+
},
|
|
3150
|
+
},
|
|
3151
|
+
reason: {
|
|
3152
|
+
type: "string",
|
|
3153
|
+
minLength: 1,
|
|
3154
|
+
maxLength: 120,
|
|
3155
|
+
},
|
|
3156
|
+
explanation: {
|
|
3157
|
+
type: "string",
|
|
3158
|
+
minLength: 1,
|
|
3159
|
+
maxLength: 1000,
|
|
3160
|
+
},
|
|
3161
|
+
evidence: {
|
|
3162
|
+
type: "string",
|
|
3163
|
+
minLength: 1,
|
|
3164
|
+
maxLength: 2000,
|
|
3165
|
+
},
|
|
3166
|
+
},
|
|
3167
|
+
};
|
|
3168
|
+
// --------------------------------------------------------------------
|
|
3169
|
+
// CodingReviewerAction (schema 1.0.0, wire coding-reviewer-action-v1)
|
|
3170
|
+
// --------------------------------------------------------------------
|
|
3171
|
+
export const codingReviewerActionSchema = z
|
|
3172
|
+
.object({
|
|
3173
|
+
reviewerId: z.string().min(1).max(128),
|
|
3174
|
+
reviewerRole: z.string().min(1).max(80).optional(),
|
|
3175
|
+
action: z.enum([
|
|
3176
|
+
"approved",
|
|
3177
|
+
"approved_with_changes",
|
|
3178
|
+
"rejected",
|
|
3179
|
+
"escalated",
|
|
3180
|
+
]),
|
|
3181
|
+
resolutionCode: z.string().min(1).max(80).optional(),
|
|
3182
|
+
notes: z
|
|
3183
|
+
.string()
|
|
3184
|
+
.min(1)
|
|
3185
|
+
.max(2000)
|
|
3186
|
+
.refine((value) => value.trim().length > 0)
|
|
3187
|
+
.optional(),
|
|
3188
|
+
occurredAt: z
|
|
3189
|
+
.string()
|
|
3190
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$"))
|
|
3191
|
+
.refine(isRfc3339DateTime)
|
|
3192
|
+
.max(64),
|
|
3193
|
+
})
|
|
3194
|
+
.strict();
|
|
3195
|
+
export function codingReviewerActionValidationError(value) {
|
|
3196
|
+
if (!isRecord(value))
|
|
3197
|
+
return "reviewer_action";
|
|
3198
|
+
if (!["reviewerId", "action", "occurredAt"].every((key) => key in value))
|
|
3199
|
+
return "reviewer_action_keys";
|
|
3200
|
+
if (!Object.keys(value).every((key) => [
|
|
3201
|
+
"reviewerId",
|
|
3202
|
+
"reviewerRole",
|
|
3203
|
+
"action",
|
|
3204
|
+
"resolutionCode",
|
|
3205
|
+
"notes",
|
|
3206
|
+
"occurredAt",
|
|
3207
|
+
].includes(key)))
|
|
3208
|
+
return "reviewer_action_keys";
|
|
3209
|
+
const value_reviewerId = value["reviewerId"];
|
|
3210
|
+
if (typeof value_reviewerId !== "string" ||
|
|
3211
|
+
value_reviewerId.length < 1 ||
|
|
3212
|
+
value_reviewerId.length > 128)
|
|
3213
|
+
return "reviewer_action_id";
|
|
3214
|
+
if (value["reviewerRole"] !== undefined) {
|
|
3215
|
+
const value_reviewerRole = value["reviewerRole"];
|
|
3216
|
+
if (typeof value_reviewerRole !== "string" ||
|
|
3217
|
+
value_reviewerRole.length < 1 ||
|
|
3218
|
+
value_reviewerRole.length > 80)
|
|
3219
|
+
return "reviewer_action_role";
|
|
3220
|
+
}
|
|
3221
|
+
const value_action = value["action"];
|
|
3222
|
+
if (typeof value_action !== "string" ||
|
|
3223
|
+
!["approved", "approved_with_changes", "rejected", "escalated"].includes(value_action))
|
|
3224
|
+
return "reviewer_action_type";
|
|
3225
|
+
if (value["resolutionCode"] !== undefined) {
|
|
3226
|
+
const value_resolutionCode = value["resolutionCode"];
|
|
3227
|
+
if (typeof value_resolutionCode !== "string" ||
|
|
3228
|
+
value_resolutionCode.length < 1 ||
|
|
3229
|
+
value_resolutionCode.length > 80)
|
|
3230
|
+
return "reviewer_action_resolution_code";
|
|
3231
|
+
}
|
|
3232
|
+
if (value["notes"] !== undefined) {
|
|
3233
|
+
const value_notes = value["notes"];
|
|
3234
|
+
if (typeof value_notes !== "string" ||
|
|
3235
|
+
value_notes.length < 1 ||
|
|
3236
|
+
value_notes.length > 2000 ||
|
|
3237
|
+
value_notes.trim().length === 0)
|
|
3238
|
+
return "reviewer_action_notes";
|
|
3239
|
+
}
|
|
3240
|
+
const value_occurredAt = value["occurredAt"];
|
|
3241
|
+
if (typeof value_occurredAt !== "string" ||
|
|
3242
|
+
value_occurredAt.length > 64 ||
|
|
3243
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$").test(value_occurredAt) ||
|
|
3244
|
+
!isRfc3339DateTime(value_occurredAt))
|
|
3245
|
+
return "reviewer_action_occurred_at";
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
export const validCodingReviewerAction = (value) => codingReviewerActionValidationError(value) === null;
|
|
3249
|
+
export const CodingReviewerActionSchemaJson = {
|
|
3250
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
3251
|
+
$id: "https://nexalink.care/contracts/coding-reviewer-action.schema.json",
|
|
3252
|
+
title: "CodingReviewerAction",
|
|
3253
|
+
description: "Attributable human-review disposition appended to an otherwise immutable decision. A decision plus its reviewer actions remains replayable: original and reviewer versions are both preserved.",
|
|
3254
|
+
version: "1.0.0",
|
|
3255
|
+
type: "object",
|
|
3256
|
+
additionalProperties: false,
|
|
3257
|
+
required: ["reviewerId", "action", "occurredAt"],
|
|
3258
|
+
properties: {
|
|
3259
|
+
reviewerId: {
|
|
3260
|
+
type: "string",
|
|
3261
|
+
minLength: 1,
|
|
3262
|
+
maxLength: 128,
|
|
3263
|
+
},
|
|
3264
|
+
reviewerRole: {
|
|
3265
|
+
type: "string",
|
|
3266
|
+
minLength: 1,
|
|
3267
|
+
maxLength: 80,
|
|
3268
|
+
},
|
|
3269
|
+
action: {
|
|
3270
|
+
type: "string",
|
|
3271
|
+
enum: ["approved", "approved_with_changes", "rejected", "escalated"],
|
|
3272
|
+
},
|
|
3273
|
+
resolutionCode: {
|
|
3274
|
+
type: "string",
|
|
3275
|
+
minLength: 1,
|
|
3276
|
+
maxLength: 80,
|
|
3277
|
+
},
|
|
3278
|
+
notes: {
|
|
3279
|
+
type: "string",
|
|
3280
|
+
minLength: 1,
|
|
3281
|
+
maxLength: 2000,
|
|
3282
|
+
},
|
|
3283
|
+
occurredAt: {
|
|
3284
|
+
type: "string",
|
|
3285
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$",
|
|
3286
|
+
format: "date-time",
|
|
3287
|
+
maxLength: 64,
|
|
3288
|
+
},
|
|
3289
|
+
},
|
|
3290
|
+
};
|
|
3291
|
+
// --------------------------------------------------------------------
|
|
3292
|
+
// CodingDecision (schema 1.0.0, wire coding-decision-v1)
|
|
3293
|
+
// --------------------------------------------------------------------
|
|
3294
|
+
export const codingDecisionSchema = z
|
|
3295
|
+
.object({
|
|
3296
|
+
decisionId: z.string().min(1).max(128),
|
|
3297
|
+
caseRef: z.string().min(1).max(128),
|
|
3298
|
+
disposition: z.enum(["review_required", "abstain", "escalate"]),
|
|
3299
|
+
humanReviewRequired: z.literal(true),
|
|
3300
|
+
rationale: z
|
|
3301
|
+
.string()
|
|
3302
|
+
.min(1)
|
|
3303
|
+
.max(4000)
|
|
3304
|
+
.refine((value) => value.trim().length > 0),
|
|
3305
|
+
overallConfidence: z.enum(["low", "medium", "high"]).optional(),
|
|
3306
|
+
lineDecisions: z.array(codingDecisionLineSchema).max(100),
|
|
3307
|
+
facts: z
|
|
3308
|
+
.array(z
|
|
3309
|
+
.object({
|
|
3310
|
+
factId: z.string().min(1).max(60),
|
|
3311
|
+
statement: z
|
|
3312
|
+
.string()
|
|
3313
|
+
.min(1)
|
|
3314
|
+
.max(2000)
|
|
3315
|
+
.refine((value) => value.trim().length > 0),
|
|
3316
|
+
evidenceRefs: z.array(z.string().min(1).max(64)).max(10).optional(),
|
|
3317
|
+
})
|
|
3318
|
+
.strict())
|
|
3319
|
+
.max(50)
|
|
3320
|
+
.optional(),
|
|
3321
|
+
gaps: z
|
|
3322
|
+
.array(z
|
|
3323
|
+
.object({
|
|
3324
|
+
gapId: z.string().min(1).max(60),
|
|
3325
|
+
type: z.enum([
|
|
3326
|
+
"missing_documentation",
|
|
3327
|
+
"unsupported_scope",
|
|
3328
|
+
"insufficient_evidence",
|
|
3329
|
+
"policy_conflict",
|
|
3330
|
+
"terminology_unavailable",
|
|
3331
|
+
"other",
|
|
3332
|
+
]),
|
|
3333
|
+
description: z
|
|
3334
|
+
.string()
|
|
3335
|
+
.min(1)
|
|
3336
|
+
.max(1000)
|
|
3337
|
+
.refine((value) => value.trim().length > 0),
|
|
3338
|
+
severity: z.enum(["low", "medium", "high", "blocking"]),
|
|
3339
|
+
})
|
|
3340
|
+
.strict())
|
|
3341
|
+
.max(30)
|
|
3342
|
+
.optional(),
|
|
3343
|
+
conflicts: z
|
|
3344
|
+
.array(z
|
|
3345
|
+
.object({
|
|
3346
|
+
conflictId: z.string().min(1).max(60),
|
|
3347
|
+
type: z.enum([
|
|
3348
|
+
"payer_vs_national",
|
|
3349
|
+
"plan_vs_contract",
|
|
3350
|
+
"terminology_period",
|
|
3351
|
+
"rule_vs_rule",
|
|
3352
|
+
"model_vs_rule",
|
|
3353
|
+
"other",
|
|
3354
|
+
]),
|
|
3355
|
+
summary: z
|
|
3356
|
+
.string()
|
|
3357
|
+
.min(1)
|
|
3358
|
+
.max(1000)
|
|
3359
|
+
.refine((value) => value.trim().length > 0),
|
|
3360
|
+
references: z.array(z.string().min(1).max(120)).max(10).optional(),
|
|
3361
|
+
})
|
|
3362
|
+
.strict())
|
|
3363
|
+
.max(20)
|
|
3364
|
+
.optional(),
|
|
3365
|
+
evidenceItems: z.array(codingEvidenceSchema).max(40).optional(),
|
|
3366
|
+
ruleTraces: z.array(codingRuleResultSchema).max(50).optional(),
|
|
3367
|
+
provenance: z
|
|
3368
|
+
.object({
|
|
3369
|
+
decisionSchemaVersion: z.string().min(1).max(40),
|
|
3370
|
+
caseSchemaVersion: z.string().min(1).max(40),
|
|
3371
|
+
pack: z
|
|
3372
|
+
.object({
|
|
3373
|
+
packId: z.string().min(1).max(120),
|
|
3374
|
+
packVersion: z.string().min(1).max(40),
|
|
3375
|
+
})
|
|
3376
|
+
.strict(),
|
|
3377
|
+
model: z
|
|
3378
|
+
.object({
|
|
3379
|
+
modelId: z.string().min(1).max(120),
|
|
3380
|
+
modelVersion: z.string().min(1).max(40),
|
|
3381
|
+
})
|
|
3382
|
+
.strict(),
|
|
3383
|
+
terminology: z
|
|
3384
|
+
.array(z
|
|
3385
|
+
.object({
|
|
3386
|
+
system: z.enum([
|
|
3387
|
+
"ICD-10-CM",
|
|
3388
|
+
"ICD-10-PCS",
|
|
3389
|
+
"CPT",
|
|
3390
|
+
"HCPCS",
|
|
3391
|
+
"NDC",
|
|
3392
|
+
"CDT",
|
|
3393
|
+
"REVENUE_CODE",
|
|
3394
|
+
"DRG",
|
|
3395
|
+
"MODIFIERS",
|
|
3396
|
+
"OTHER",
|
|
3397
|
+
]),
|
|
3398
|
+
editionVersion: z.string().min(1).max(40),
|
|
3399
|
+
licenseApproved: z.boolean(),
|
|
3400
|
+
})
|
|
3401
|
+
.strict())
|
|
3402
|
+
.max(20),
|
|
3403
|
+
rules: z
|
|
3404
|
+
.array(z
|
|
3405
|
+
.object({
|
|
3406
|
+
ruleId: z.string().min(1).max(120),
|
|
3407
|
+
ruleVersion: z.string().min(1).max(40),
|
|
3408
|
+
})
|
|
3409
|
+
.strict())
|
|
3410
|
+
.max(30),
|
|
3411
|
+
retrievalCorpus: z
|
|
3412
|
+
.object({
|
|
3413
|
+
corpusId: z.string().min(1).max(120).optional(),
|
|
3414
|
+
corpusVersion: z.string().min(1).max(120).optional(),
|
|
3415
|
+
})
|
|
3416
|
+
.strict()
|
|
3417
|
+
.optional(),
|
|
3418
|
+
generatedAt: z
|
|
3419
|
+
.string()
|
|
3420
|
+
.regex(new RegExp("^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$"))
|
|
3421
|
+
.refine(isRfc3339DateTime)
|
|
3422
|
+
.max(64),
|
|
3423
|
+
})
|
|
3424
|
+
.strict(),
|
|
3425
|
+
reviewerAction: codingReviewerActionSchema.optional(),
|
|
3426
|
+
extensions: z.array(codingExtensionSchema).max(25).optional(),
|
|
3427
|
+
})
|
|
3428
|
+
.strict()
|
|
3429
|
+
.superRefine((value, ctx) => {
|
|
3430
|
+
if (value["disposition"] === "review_required") {
|
|
3431
|
+
if (!Array.isArray(value["lineDecisions"]) ||
|
|
3432
|
+
value["lineDecisions"].length === 0) {
|
|
3433
|
+
ctx.addIssue({
|
|
3434
|
+
code: "custom",
|
|
3435
|
+
path: ["lineDecisions"],
|
|
3436
|
+
message: "decision_review_required_lines",
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
else {
|
|
3441
|
+
if (Array.isArray(value["lineDecisions"]) &&
|
|
3442
|
+
value["lineDecisions"].length > 0) {
|
|
3443
|
+
ctx.addIssue({
|
|
3444
|
+
code: "custom",
|
|
3445
|
+
path: ["lineDecisions"],
|
|
3446
|
+
message: "decision_disposition_lines",
|
|
3447
|
+
});
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
})
|
|
3451
|
+
.superRefine((value, ctx) => {
|
|
3452
|
+
const semanticValue = value;
|
|
3453
|
+
const provenance = isRecord(semanticValue["provenance"])
|
|
3454
|
+
? semanticValue["provenance"]
|
|
3455
|
+
: {};
|
|
3456
|
+
if (Array.isArray(semanticValue["lineDecisions"]) &&
|
|
3457
|
+
semanticValue["lineDecisions"].length > 0 &&
|
|
3458
|
+
(!Array.isArray(provenance["terminology"]) ||
|
|
3459
|
+
provenance["terminology"].length === 0 ||
|
|
3460
|
+
!Array.isArray(provenance["rules"]) ||
|
|
3461
|
+
provenance["rules"].length === 0)) {
|
|
3462
|
+
ctx.addIssue({
|
|
3463
|
+
code: "custom",
|
|
3464
|
+
path: ["provenance"],
|
|
3465
|
+
message: "decision_provenance_replay",
|
|
3466
|
+
});
|
|
3467
|
+
}
|
|
3468
|
+
});
|
|
3469
|
+
export function codingDecisionValidationError(value, options) {
|
|
3470
|
+
if (!isRecord(value))
|
|
3471
|
+
return "coding_decision";
|
|
3472
|
+
if (![
|
|
3473
|
+
"decisionId",
|
|
3474
|
+
"caseRef",
|
|
3475
|
+
"disposition",
|
|
3476
|
+
"humanReviewRequired",
|
|
3477
|
+
"rationale",
|
|
3478
|
+
"lineDecisions",
|
|
3479
|
+
"provenance",
|
|
3480
|
+
].every((key) => key in value))
|
|
3481
|
+
return "coding_decision_keys";
|
|
3482
|
+
if (!Object.keys(value).every((key) => [
|
|
3483
|
+
"decisionId",
|
|
3484
|
+
"caseRef",
|
|
3485
|
+
"disposition",
|
|
3486
|
+
"humanReviewRequired",
|
|
3487
|
+
"rationale",
|
|
3488
|
+
"overallConfidence",
|
|
3489
|
+
"lineDecisions",
|
|
3490
|
+
"facts",
|
|
3491
|
+
"gaps",
|
|
3492
|
+
"conflicts",
|
|
3493
|
+
"evidenceItems",
|
|
3494
|
+
"ruleTraces",
|
|
3495
|
+
"provenance",
|
|
3496
|
+
"reviewerAction",
|
|
3497
|
+
"extensions",
|
|
3498
|
+
].includes(key)))
|
|
3499
|
+
return "coding_decision_keys";
|
|
3500
|
+
const value_decisionId = value["decisionId"];
|
|
3501
|
+
if (typeof value_decisionId !== "string" ||
|
|
3502
|
+
value_decisionId.length < 1 ||
|
|
3503
|
+
value_decisionId.length > 128)
|
|
3504
|
+
return "decision_id";
|
|
3505
|
+
const value_caseRef = value["caseRef"];
|
|
3506
|
+
if (typeof value_caseRef !== "string" ||
|
|
3507
|
+
value_caseRef.length < 1 ||
|
|
3508
|
+
value_caseRef.length > 128)
|
|
3509
|
+
return "decision_case_ref";
|
|
3510
|
+
const value_disposition = value["disposition"];
|
|
3511
|
+
if (typeof value_disposition !== "string" ||
|
|
3512
|
+
!["review_required", "abstain", "escalate"].includes(value_disposition))
|
|
3513
|
+
return "decision_disposition";
|
|
3514
|
+
const value_humanReviewRequired = value["humanReviewRequired"];
|
|
3515
|
+
if (typeof value_humanReviewRequired !== "boolean" ||
|
|
3516
|
+
value_humanReviewRequired !== true)
|
|
3517
|
+
return "decision_human_review_required";
|
|
3518
|
+
const value_rationale = value["rationale"];
|
|
3519
|
+
if (typeof value_rationale !== "string" ||
|
|
3520
|
+
value_rationale.length < 1 ||
|
|
3521
|
+
value_rationale.length > 4000 ||
|
|
3522
|
+
value_rationale.trim().length === 0)
|
|
3523
|
+
return "decision_rationale";
|
|
3524
|
+
if (value["overallConfidence"] !== undefined) {
|
|
3525
|
+
const value_overallConfidence = value["overallConfidence"];
|
|
3526
|
+
if (typeof value_overallConfidence !== "string" ||
|
|
3527
|
+
!["low", "medium", "high"].includes(value_overallConfidence))
|
|
3528
|
+
return "decision_overall_confidence";
|
|
3529
|
+
}
|
|
3530
|
+
const value_lineDecisions = value["lineDecisions"];
|
|
3531
|
+
if (!Array.isArray(value_lineDecisions) || value_lineDecisions.length > 100)
|
|
3532
|
+
return "decision_lines";
|
|
3533
|
+
for (const item of value_lineDecisions) {
|
|
3534
|
+
const itemRefError = codingDecisionLineValidationError(item);
|
|
3535
|
+
if (itemRefError !== null)
|
|
3536
|
+
return itemRefError;
|
|
3537
|
+
}
|
|
3538
|
+
if (value["facts"] !== undefined) {
|
|
3539
|
+
const value_facts = value["facts"];
|
|
3540
|
+
if (!Array.isArray(value_facts) || value_facts.length > 50)
|
|
3541
|
+
return "decision_facts";
|
|
3542
|
+
for (const item of value_facts) {
|
|
3543
|
+
if (!isRecord(item))
|
|
3544
|
+
return "decision_fact";
|
|
3545
|
+
if (!["factId", "statement"].every((key) => key in item))
|
|
3546
|
+
return "decision_fact_keys";
|
|
3547
|
+
if (!Object.keys(item).every((key) => ["factId", "statement", "evidenceRefs"].includes(key)))
|
|
3548
|
+
return "decision_fact_keys";
|
|
3549
|
+
const item_factId = item["factId"];
|
|
3550
|
+
if (typeof item_factId !== "string" ||
|
|
3551
|
+
item_factId.length < 1 ||
|
|
3552
|
+
item_factId.length > 60)
|
|
3553
|
+
return "decision_fact_id";
|
|
3554
|
+
const item_statement = item["statement"];
|
|
3555
|
+
if (typeof item_statement !== "string" ||
|
|
3556
|
+
item_statement.length < 1 ||
|
|
3557
|
+
item_statement.length > 2000 ||
|
|
3558
|
+
item_statement.trim().length === 0)
|
|
3559
|
+
return "decision_fact_statement";
|
|
3560
|
+
if (item["evidenceRefs"] !== undefined) {
|
|
3561
|
+
const item_evidenceRefs = item["evidenceRefs"];
|
|
3562
|
+
if (!Array.isArray(item_evidenceRefs) || item_evidenceRefs.length > 10)
|
|
3563
|
+
return "decision_fact_evidence_refs";
|
|
3564
|
+
for (const item of item_evidenceRefs) {
|
|
3565
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 64)
|
|
3566
|
+
return "decision_fact_evidence_refs";
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
if (value["gaps"] !== undefined) {
|
|
3572
|
+
const value_gaps = value["gaps"];
|
|
3573
|
+
if (!Array.isArray(value_gaps) || value_gaps.length > 30)
|
|
3574
|
+
return "decision_gaps";
|
|
3575
|
+
for (const item of value_gaps) {
|
|
3576
|
+
if (!isRecord(item))
|
|
3577
|
+
return "decision_gap";
|
|
3578
|
+
if (!["gapId", "type", "description", "severity"].every((key) => key in item))
|
|
3579
|
+
return "decision_gap_keys";
|
|
3580
|
+
if (!Object.keys(item).every((key) => ["gapId", "type", "description", "severity"].includes(key)))
|
|
3581
|
+
return "decision_gap_keys";
|
|
3582
|
+
const item_gapId = item["gapId"];
|
|
3583
|
+
if (typeof item_gapId !== "string" ||
|
|
3584
|
+
item_gapId.length < 1 ||
|
|
3585
|
+
item_gapId.length > 60)
|
|
3586
|
+
return "decision_gap_id";
|
|
3587
|
+
const item_type = item["type"];
|
|
3588
|
+
if (typeof item_type !== "string" ||
|
|
3589
|
+
![
|
|
3590
|
+
"missing_documentation",
|
|
3591
|
+
"unsupported_scope",
|
|
3592
|
+
"insufficient_evidence",
|
|
3593
|
+
"policy_conflict",
|
|
3594
|
+
"terminology_unavailable",
|
|
3595
|
+
"other",
|
|
3596
|
+
].includes(item_type))
|
|
3597
|
+
return "decision_gap_type";
|
|
3598
|
+
const item_description = item["description"];
|
|
3599
|
+
if (typeof item_description !== "string" ||
|
|
3600
|
+
item_description.length < 1 ||
|
|
3601
|
+
item_description.length > 1000 ||
|
|
3602
|
+
item_description.trim().length === 0)
|
|
3603
|
+
return "decision_gap_description";
|
|
3604
|
+
const item_severity = item["severity"];
|
|
3605
|
+
if (typeof item_severity !== "string" ||
|
|
3606
|
+
!["low", "medium", "high", "blocking"].includes(item_severity))
|
|
3607
|
+
return "decision_gap_severity";
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
if (value["conflicts"] !== undefined) {
|
|
3611
|
+
const value_conflicts = value["conflicts"];
|
|
3612
|
+
if (!Array.isArray(value_conflicts) || value_conflicts.length > 20)
|
|
3613
|
+
return "decision_conflicts";
|
|
3614
|
+
for (const item of value_conflicts) {
|
|
3615
|
+
if (!isRecord(item))
|
|
3616
|
+
return "decision_conflict";
|
|
3617
|
+
if (!["conflictId", "type", "summary"].every((key) => key in item))
|
|
3618
|
+
return "decision_conflict_keys";
|
|
3619
|
+
if (!Object.keys(item).every((key) => ["conflictId", "type", "summary", "references"].includes(key)))
|
|
3620
|
+
return "decision_conflict_keys";
|
|
3621
|
+
const item_conflictId = item["conflictId"];
|
|
3622
|
+
if (typeof item_conflictId !== "string" ||
|
|
3623
|
+
item_conflictId.length < 1 ||
|
|
3624
|
+
item_conflictId.length > 60)
|
|
3625
|
+
return "decision_conflict_id";
|
|
3626
|
+
const item_type = item["type"];
|
|
3627
|
+
if (typeof item_type !== "string" ||
|
|
3628
|
+
![
|
|
3629
|
+
"payer_vs_national",
|
|
3630
|
+
"plan_vs_contract",
|
|
3631
|
+
"terminology_period",
|
|
3632
|
+
"rule_vs_rule",
|
|
3633
|
+
"model_vs_rule",
|
|
3634
|
+
"other",
|
|
3635
|
+
].includes(item_type))
|
|
3636
|
+
return "decision_conflict_type";
|
|
3637
|
+
const item_summary = item["summary"];
|
|
3638
|
+
if (typeof item_summary !== "string" ||
|
|
3639
|
+
item_summary.length < 1 ||
|
|
3640
|
+
item_summary.length > 1000 ||
|
|
3641
|
+
item_summary.trim().length === 0)
|
|
3642
|
+
return "decision_conflict_summary";
|
|
3643
|
+
if (item["references"] !== undefined) {
|
|
3644
|
+
const item_references = item["references"];
|
|
3645
|
+
if (!Array.isArray(item_references) || item_references.length > 10)
|
|
3646
|
+
return "decision_conflict_references";
|
|
3647
|
+
for (const item of item_references) {
|
|
3648
|
+
if (typeof item !== "string" || item.length < 1 || item.length > 120)
|
|
3649
|
+
return "decision_conflict_references";
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
if (value["evidenceItems"] !== undefined) {
|
|
3655
|
+
const value_evidenceItems = value["evidenceItems"];
|
|
3656
|
+
if (!Array.isArray(value_evidenceItems) || value_evidenceItems.length > 40)
|
|
3657
|
+
return "decision_evidence_items";
|
|
3658
|
+
for (const item of value_evidenceItems) {
|
|
3659
|
+
const itemRefError = codingEvidenceValidationError(item);
|
|
3660
|
+
if (itemRefError !== null)
|
|
3661
|
+
return itemRefError;
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
if (value["ruleTraces"] !== undefined) {
|
|
3665
|
+
const value_ruleTraces = value["ruleTraces"];
|
|
3666
|
+
if (!Array.isArray(value_ruleTraces) || value_ruleTraces.length > 50)
|
|
3667
|
+
return "decision_rule_traces";
|
|
3668
|
+
for (const item of value_ruleTraces) {
|
|
3669
|
+
const itemRefError = codingRuleResultValidationError(item);
|
|
3670
|
+
if (itemRefError !== null)
|
|
3671
|
+
return itemRefError;
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
const value_provenance = value["provenance"];
|
|
3675
|
+
if (!isRecord(value_provenance))
|
|
3676
|
+
return "decision_provenance";
|
|
3677
|
+
if (![
|
|
3678
|
+
"decisionSchemaVersion",
|
|
3679
|
+
"caseSchemaVersion",
|
|
3680
|
+
"pack",
|
|
3681
|
+
"model",
|
|
3682
|
+
"terminology",
|
|
3683
|
+
"rules",
|
|
3684
|
+
"generatedAt",
|
|
3685
|
+
].every((key) => key in value_provenance))
|
|
3686
|
+
return "decision_provenance_keys";
|
|
3687
|
+
if (!Object.keys(value_provenance).every((key) => [
|
|
3688
|
+
"decisionSchemaVersion",
|
|
3689
|
+
"caseSchemaVersion",
|
|
3690
|
+
"pack",
|
|
3691
|
+
"model",
|
|
3692
|
+
"terminology",
|
|
3693
|
+
"rules",
|
|
3694
|
+
"retrievalCorpus",
|
|
3695
|
+
"generatedAt",
|
|
3696
|
+
].includes(key)))
|
|
3697
|
+
return "decision_provenance_keys";
|
|
3698
|
+
const value_provenance_decisionSchemaVersion = value_provenance["decisionSchemaVersion"];
|
|
3699
|
+
if (typeof value_provenance_decisionSchemaVersion !== "string" ||
|
|
3700
|
+
value_provenance_decisionSchemaVersion.length < 1 ||
|
|
3701
|
+
value_provenance_decisionSchemaVersion.length > 40)
|
|
3702
|
+
return "decision_provenance_decision_schema_version";
|
|
3703
|
+
const value_provenance_caseSchemaVersion = value_provenance["caseSchemaVersion"];
|
|
3704
|
+
if (typeof value_provenance_caseSchemaVersion !== "string" ||
|
|
3705
|
+
value_provenance_caseSchemaVersion.length < 1 ||
|
|
3706
|
+
value_provenance_caseSchemaVersion.length > 40)
|
|
3707
|
+
return "decision_provenance_case_schema_version";
|
|
3708
|
+
const value_provenance_pack = value_provenance["pack"];
|
|
3709
|
+
if (!isRecord(value_provenance_pack))
|
|
3710
|
+
return "decision_provenance_pack";
|
|
3711
|
+
if (!["packId", "packVersion"].every((key) => key in value_provenance_pack))
|
|
3712
|
+
return "decision_provenance_pack_keys";
|
|
3713
|
+
if (!Object.keys(value_provenance_pack).every((key) => ["packId", "packVersion"].includes(key)))
|
|
3714
|
+
return "decision_provenance_pack_keys";
|
|
3715
|
+
const value_provenance_pack_packId = value_provenance_pack["packId"];
|
|
3716
|
+
if (typeof value_provenance_pack_packId !== "string" ||
|
|
3717
|
+
value_provenance_pack_packId.length < 1 ||
|
|
3718
|
+
value_provenance_pack_packId.length > 120)
|
|
3719
|
+
return "decision_provenance_pack_id";
|
|
3720
|
+
const value_provenance_pack_packVersion = value_provenance_pack["packVersion"];
|
|
3721
|
+
if (typeof value_provenance_pack_packVersion !== "string" ||
|
|
3722
|
+
value_provenance_pack_packVersion.length < 1 ||
|
|
3723
|
+
value_provenance_pack_packVersion.length > 40)
|
|
3724
|
+
return "decision_provenance_pack_version";
|
|
3725
|
+
const value_provenance_model = value_provenance["model"];
|
|
3726
|
+
if (!isRecord(value_provenance_model))
|
|
3727
|
+
return "decision_provenance_model";
|
|
3728
|
+
if (!["modelId", "modelVersion"].every((key) => key in value_provenance_model))
|
|
3729
|
+
return "decision_provenance_model_keys";
|
|
3730
|
+
if (!Object.keys(value_provenance_model).every((key) => ["modelId", "modelVersion"].includes(key)))
|
|
3731
|
+
return "decision_provenance_model_keys";
|
|
3732
|
+
const value_provenance_model_modelId = value_provenance_model["modelId"];
|
|
3733
|
+
if (typeof value_provenance_model_modelId !== "string" ||
|
|
3734
|
+
value_provenance_model_modelId.length < 1 ||
|
|
3735
|
+
value_provenance_model_modelId.length > 120)
|
|
3736
|
+
return "decision_provenance_model_id";
|
|
3737
|
+
const value_provenance_model_modelVersion = value_provenance_model["modelVersion"];
|
|
3738
|
+
if (typeof value_provenance_model_modelVersion !== "string" ||
|
|
3739
|
+
value_provenance_model_modelVersion.length < 1 ||
|
|
3740
|
+
value_provenance_model_modelVersion.length > 40)
|
|
3741
|
+
return "decision_provenance_model_version";
|
|
3742
|
+
const value_provenance_terminology = value_provenance["terminology"];
|
|
3743
|
+
if (!Array.isArray(value_provenance_terminology) ||
|
|
3744
|
+
value_provenance_terminology.length > 20)
|
|
3745
|
+
return "decision_provenance_terminology";
|
|
3746
|
+
for (const item of value_provenance_terminology) {
|
|
3747
|
+
if (!isRecord(item))
|
|
3748
|
+
return "decision_provenance_terminology_item";
|
|
3749
|
+
if (!["system", "editionVersion", "licenseApproved"].every((key) => key in item))
|
|
3750
|
+
return "decision_provenance_terminology_item_keys";
|
|
3751
|
+
if (!Object.keys(item).every((key) => ["system", "editionVersion", "licenseApproved"].includes(key)))
|
|
3752
|
+
return "decision_provenance_terminology_item_keys";
|
|
3753
|
+
const item_system = item["system"];
|
|
3754
|
+
if (typeof item_system !== "string" ||
|
|
3755
|
+
![
|
|
3756
|
+
"ICD-10-CM",
|
|
3757
|
+
"ICD-10-PCS",
|
|
3758
|
+
"CPT",
|
|
3759
|
+
"HCPCS",
|
|
3760
|
+
"NDC",
|
|
3761
|
+
"CDT",
|
|
3762
|
+
"REVENUE_CODE",
|
|
3763
|
+
"DRG",
|
|
3764
|
+
"MODIFIERS",
|
|
3765
|
+
"OTHER",
|
|
3766
|
+
].includes(item_system))
|
|
3767
|
+
return "decision_provenance_terminology_system";
|
|
3768
|
+
const item_editionVersion = item["editionVersion"];
|
|
3769
|
+
if (typeof item_editionVersion !== "string" ||
|
|
3770
|
+
item_editionVersion.length < 1 ||
|
|
3771
|
+
item_editionVersion.length > 40)
|
|
3772
|
+
return "decision_provenance_terminology_edition";
|
|
3773
|
+
const item_licenseApproved = item["licenseApproved"];
|
|
3774
|
+
if (typeof item_licenseApproved !== "boolean")
|
|
3775
|
+
return "decision_provenance_terminology_license";
|
|
3776
|
+
}
|
|
3777
|
+
const value_provenance_rules = value_provenance["rules"];
|
|
3778
|
+
if (!Array.isArray(value_provenance_rules) ||
|
|
3779
|
+
value_provenance_rules.length > 30)
|
|
3780
|
+
return "decision_provenance_rules";
|
|
3781
|
+
for (const item of value_provenance_rules) {
|
|
3782
|
+
if (!isRecord(item))
|
|
3783
|
+
return "decision_provenance_rule";
|
|
3784
|
+
if (!["ruleId", "ruleVersion"].every((key) => key in item))
|
|
3785
|
+
return "decision_provenance_rule_keys";
|
|
3786
|
+
if (!Object.keys(item).every((key) => ["ruleId", "ruleVersion"].includes(key)))
|
|
3787
|
+
return "decision_provenance_rule_keys";
|
|
3788
|
+
const item_ruleId = item["ruleId"];
|
|
3789
|
+
if (typeof item_ruleId !== "string" ||
|
|
3790
|
+
item_ruleId.length < 1 ||
|
|
3791
|
+
item_ruleId.length > 120)
|
|
3792
|
+
return "decision_provenance_rule_id";
|
|
3793
|
+
const item_ruleVersion = item["ruleVersion"];
|
|
3794
|
+
if (typeof item_ruleVersion !== "string" ||
|
|
3795
|
+
item_ruleVersion.length < 1 ||
|
|
3796
|
+
item_ruleVersion.length > 40)
|
|
3797
|
+
return "decision_provenance_rule_version";
|
|
3798
|
+
}
|
|
3799
|
+
if (value_provenance["retrievalCorpus"] !== undefined) {
|
|
3800
|
+
const value_provenance_retrievalCorpus = value_provenance["retrievalCorpus"];
|
|
3801
|
+
if (!isRecord(value_provenance_retrievalCorpus))
|
|
3802
|
+
return "decision_provenance_corpus";
|
|
3803
|
+
if (!Object.keys(value_provenance_retrievalCorpus).every((key) => ["corpusId", "corpusVersion"].includes(key)))
|
|
3804
|
+
return "decision_provenance_corpus_keys";
|
|
3805
|
+
if (value_provenance_retrievalCorpus["corpusId"] !== undefined) {
|
|
3806
|
+
const value_provenance_retrievalCorpus_corpusId = value_provenance_retrievalCorpus["corpusId"];
|
|
3807
|
+
if (typeof value_provenance_retrievalCorpus_corpusId !== "string" ||
|
|
3808
|
+
value_provenance_retrievalCorpus_corpusId.length < 1 ||
|
|
3809
|
+
value_provenance_retrievalCorpus_corpusId.length > 120)
|
|
3810
|
+
return "decision_provenance_corpus_id";
|
|
3811
|
+
}
|
|
3812
|
+
if (value_provenance_retrievalCorpus["corpusVersion"] !== undefined) {
|
|
3813
|
+
const value_provenance_retrievalCorpus_corpusVersion = value_provenance_retrievalCorpus["corpusVersion"];
|
|
3814
|
+
if (typeof value_provenance_retrievalCorpus_corpusVersion !== "string" ||
|
|
3815
|
+
value_provenance_retrievalCorpus_corpusVersion.length < 1 ||
|
|
3816
|
+
value_provenance_retrievalCorpus_corpusVersion.length > 120)
|
|
3817
|
+
return "decision_provenance_corpus_version";
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
const value_provenance_generatedAt = value_provenance["generatedAt"];
|
|
3821
|
+
if (typeof value_provenance_generatedAt !== "string" ||
|
|
3822
|
+
value_provenance_generatedAt.length > 64 ||
|
|
3823
|
+
!new RegExp("^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$").test(value_provenance_generatedAt) ||
|
|
3824
|
+
!isRfc3339DateTime(value_provenance_generatedAt))
|
|
3825
|
+
return "decision_provenance_generated_at";
|
|
3826
|
+
if (value["reviewerAction"] !== undefined) {
|
|
3827
|
+
const value_reviewerAction = value["reviewerAction"];
|
|
3828
|
+
const value_reviewerActionRefError = codingReviewerActionValidationError(value_reviewerAction);
|
|
3829
|
+
if (value_reviewerActionRefError !== null)
|
|
3830
|
+
return value_reviewerActionRefError;
|
|
3831
|
+
}
|
|
3832
|
+
if (value["extensions"] !== undefined) {
|
|
3833
|
+
const value_extensions = value["extensions"];
|
|
3834
|
+
if (!Array.isArray(value_extensions) || value_extensions.length > 25)
|
|
3835
|
+
return "decision_extensions";
|
|
3836
|
+
for (const item of value_extensions) {
|
|
3837
|
+
const itemRefError = codingExtensionValidationError(item);
|
|
3838
|
+
if (itemRefError !== null)
|
|
3839
|
+
return itemRefError;
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
if (value["disposition"] === "review_required") {
|
|
3843
|
+
if (!Array.isArray(value["lineDecisions"]) ||
|
|
3844
|
+
value["lineDecisions"].length === 0)
|
|
3845
|
+
return "decision_review_required_lines";
|
|
3846
|
+
}
|
|
3847
|
+
else {
|
|
3848
|
+
if (Array.isArray(value["lineDecisions"]) &&
|
|
3849
|
+
value["lineDecisions"].length > 0)
|
|
3850
|
+
return "decision_disposition_lines";
|
|
3851
|
+
}
|
|
3852
|
+
if (Array.isArray(value["lineDecisions"]) &&
|
|
3853
|
+
value["lineDecisions"].length > 0) {
|
|
3854
|
+
const provenance = isRecord(value["provenance"]) ? value["provenance"] : {};
|
|
3855
|
+
if (!Array.isArray(provenance["terminology"]) ||
|
|
3856
|
+
provenance["terminology"].length === 0 ||
|
|
3857
|
+
!Array.isArray(provenance["rules"]) ||
|
|
3858
|
+
provenance["rules"].length === 0)
|
|
3859
|
+
return "decision_provenance_replay";
|
|
3860
|
+
}
|
|
3861
|
+
return null;
|
|
3862
|
+
}
|
|
3863
|
+
export const validCodingDecision = (value) => codingDecisionValidationError(value) === null;
|
|
3864
|
+
export const CodingDecisionSchemaJson = {
|
|
3865
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
3866
|
+
$id: "https://nexalink.care/contracts/coding-decision.schema.json",
|
|
3867
|
+
title: "CodingDecision",
|
|
3868
|
+
description: "The canonical, reconstructable decision for a CodingCase. caseRef is an analytics-safe reference (the case's analyticsId or a runtime opaque reference) and never a direct identifier. provenance pins the pack, model, terminology, rules, and schema versions needed to replay every recommendation.",
|
|
3869
|
+
version: "1.0.0",
|
|
3870
|
+
type: "object",
|
|
3871
|
+
additionalProperties: false,
|
|
3872
|
+
required: [
|
|
3873
|
+
"decisionId",
|
|
3874
|
+
"caseRef",
|
|
3875
|
+
"disposition",
|
|
3876
|
+
"humanReviewRequired",
|
|
3877
|
+
"rationale",
|
|
3878
|
+
"lineDecisions",
|
|
3879
|
+
"provenance",
|
|
3880
|
+
],
|
|
3881
|
+
properties: {
|
|
3882
|
+
decisionId: {
|
|
3883
|
+
type: "string",
|
|
3884
|
+
minLength: 1,
|
|
3885
|
+
maxLength: 128,
|
|
3886
|
+
},
|
|
3887
|
+
caseRef: {
|
|
3888
|
+
type: "string",
|
|
3889
|
+
minLength: 1,
|
|
3890
|
+
maxLength: 128,
|
|
3891
|
+
},
|
|
3892
|
+
disposition: {
|
|
3893
|
+
type: "string",
|
|
3894
|
+
enum: ["review_required", "abstain", "escalate"],
|
|
3895
|
+
},
|
|
3896
|
+
humanReviewRequired: {
|
|
3897
|
+
type: "boolean",
|
|
3898
|
+
const: true,
|
|
3899
|
+
},
|
|
3900
|
+
rationale: {
|
|
3901
|
+
type: "string",
|
|
3902
|
+
minLength: 1,
|
|
3903
|
+
maxLength: 4000,
|
|
3904
|
+
},
|
|
3905
|
+
overallConfidence: {
|
|
3906
|
+
type: "string",
|
|
3907
|
+
enum: ["low", "medium", "high"],
|
|
3908
|
+
},
|
|
3909
|
+
lineDecisions: {
|
|
3910
|
+
type: "array",
|
|
3911
|
+
maxItems: 100,
|
|
3912
|
+
items: {
|
|
3913
|
+
$ref: "coding-decision-line.schema.json",
|
|
3914
|
+
},
|
|
3915
|
+
},
|
|
3916
|
+
facts: {
|
|
3917
|
+
type: "array",
|
|
3918
|
+
maxItems: 50,
|
|
3919
|
+
items: {
|
|
3920
|
+
type: "object",
|
|
3921
|
+
additionalProperties: false,
|
|
3922
|
+
required: ["factId", "statement"],
|
|
3923
|
+
properties: {
|
|
3924
|
+
factId: {
|
|
3925
|
+
type: "string",
|
|
3926
|
+
minLength: 1,
|
|
3927
|
+
maxLength: 60,
|
|
3928
|
+
},
|
|
3929
|
+
statement: {
|
|
3930
|
+
type: "string",
|
|
3931
|
+
minLength: 1,
|
|
3932
|
+
maxLength: 2000,
|
|
3933
|
+
},
|
|
3934
|
+
evidenceRefs: {
|
|
3935
|
+
type: "array",
|
|
3936
|
+
maxItems: 10,
|
|
3937
|
+
items: {
|
|
3938
|
+
type: "string",
|
|
3939
|
+
minLength: 1,
|
|
3940
|
+
maxLength: 64,
|
|
3941
|
+
},
|
|
3942
|
+
},
|
|
3943
|
+
},
|
|
3944
|
+
},
|
|
3945
|
+
},
|
|
3946
|
+
gaps: {
|
|
3947
|
+
type: "array",
|
|
3948
|
+
maxItems: 30,
|
|
3949
|
+
items: {
|
|
3950
|
+
type: "object",
|
|
3951
|
+
additionalProperties: false,
|
|
3952
|
+
required: ["gapId", "type", "description", "severity"],
|
|
3953
|
+
properties: {
|
|
3954
|
+
gapId: {
|
|
3955
|
+
type: "string",
|
|
3956
|
+
minLength: 1,
|
|
3957
|
+
maxLength: 60,
|
|
3958
|
+
},
|
|
3959
|
+
type: {
|
|
3960
|
+
type: "string",
|
|
3961
|
+
enum: [
|
|
3962
|
+
"missing_documentation",
|
|
3963
|
+
"unsupported_scope",
|
|
3964
|
+
"insufficient_evidence",
|
|
3965
|
+
"policy_conflict",
|
|
3966
|
+
"terminology_unavailable",
|
|
3967
|
+
"other",
|
|
3968
|
+
],
|
|
3969
|
+
},
|
|
3970
|
+
description: {
|
|
3971
|
+
type: "string",
|
|
3972
|
+
minLength: 1,
|
|
3973
|
+
maxLength: 1000,
|
|
3974
|
+
},
|
|
3975
|
+
severity: {
|
|
3976
|
+
type: "string",
|
|
3977
|
+
enum: ["low", "medium", "high", "blocking"],
|
|
3978
|
+
},
|
|
3979
|
+
},
|
|
3980
|
+
},
|
|
3981
|
+
},
|
|
3982
|
+
conflicts: {
|
|
3983
|
+
type: "array",
|
|
3984
|
+
maxItems: 20,
|
|
3985
|
+
items: {
|
|
3986
|
+
type: "object",
|
|
3987
|
+
additionalProperties: false,
|
|
3988
|
+
required: ["conflictId", "type", "summary"],
|
|
3989
|
+
properties: {
|
|
3990
|
+
conflictId: {
|
|
3991
|
+
type: "string",
|
|
3992
|
+
minLength: 1,
|
|
3993
|
+
maxLength: 60,
|
|
3994
|
+
},
|
|
3995
|
+
type: {
|
|
3996
|
+
type: "string",
|
|
3997
|
+
enum: [
|
|
3998
|
+
"payer_vs_national",
|
|
3999
|
+
"plan_vs_contract",
|
|
4000
|
+
"terminology_period",
|
|
4001
|
+
"rule_vs_rule",
|
|
4002
|
+
"model_vs_rule",
|
|
4003
|
+
"other",
|
|
4004
|
+
],
|
|
4005
|
+
},
|
|
4006
|
+
summary: {
|
|
4007
|
+
type: "string",
|
|
4008
|
+
minLength: 1,
|
|
4009
|
+
maxLength: 1000,
|
|
4010
|
+
},
|
|
4011
|
+
references: {
|
|
4012
|
+
type: "array",
|
|
4013
|
+
maxItems: 10,
|
|
4014
|
+
items: {
|
|
4015
|
+
type: "string",
|
|
4016
|
+
minLength: 1,
|
|
4017
|
+
maxLength: 120,
|
|
4018
|
+
},
|
|
4019
|
+
},
|
|
4020
|
+
},
|
|
4021
|
+
},
|
|
4022
|
+
},
|
|
4023
|
+
evidenceItems: {
|
|
4024
|
+
type: "array",
|
|
4025
|
+
maxItems: 40,
|
|
4026
|
+
items: {
|
|
4027
|
+
$ref: "coding-evidence.schema.json",
|
|
4028
|
+
},
|
|
4029
|
+
},
|
|
4030
|
+
ruleTraces: {
|
|
4031
|
+
type: "array",
|
|
4032
|
+
maxItems: 50,
|
|
4033
|
+
items: {
|
|
4034
|
+
$ref: "coding-rule-result.schema.json",
|
|
4035
|
+
},
|
|
4036
|
+
},
|
|
4037
|
+
provenance: {
|
|
4038
|
+
type: "object",
|
|
4039
|
+
additionalProperties: false,
|
|
4040
|
+
required: [
|
|
4041
|
+
"decisionSchemaVersion",
|
|
4042
|
+
"caseSchemaVersion",
|
|
4043
|
+
"pack",
|
|
4044
|
+
"model",
|
|
4045
|
+
"terminology",
|
|
4046
|
+
"rules",
|
|
4047
|
+
"generatedAt",
|
|
4048
|
+
],
|
|
4049
|
+
properties: {
|
|
4050
|
+
decisionSchemaVersion: {
|
|
4051
|
+
type: "string",
|
|
4052
|
+
minLength: 1,
|
|
4053
|
+
maxLength: 40,
|
|
4054
|
+
},
|
|
4055
|
+
caseSchemaVersion: {
|
|
4056
|
+
type: "string",
|
|
4057
|
+
minLength: 1,
|
|
4058
|
+
maxLength: 40,
|
|
4059
|
+
},
|
|
4060
|
+
pack: {
|
|
4061
|
+
type: "object",
|
|
4062
|
+
additionalProperties: false,
|
|
4063
|
+
required: ["packId", "packVersion"],
|
|
4064
|
+
properties: {
|
|
4065
|
+
packId: {
|
|
4066
|
+
type: "string",
|
|
4067
|
+
minLength: 1,
|
|
4068
|
+
maxLength: 120,
|
|
4069
|
+
},
|
|
4070
|
+
packVersion: {
|
|
4071
|
+
type: "string",
|
|
4072
|
+
minLength: 1,
|
|
4073
|
+
maxLength: 40,
|
|
4074
|
+
},
|
|
4075
|
+
},
|
|
4076
|
+
},
|
|
4077
|
+
model: {
|
|
4078
|
+
type: "object",
|
|
4079
|
+
additionalProperties: false,
|
|
4080
|
+
required: ["modelId", "modelVersion"],
|
|
4081
|
+
properties: {
|
|
4082
|
+
modelId: {
|
|
4083
|
+
type: "string",
|
|
4084
|
+
minLength: 1,
|
|
4085
|
+
maxLength: 120,
|
|
4086
|
+
},
|
|
4087
|
+
modelVersion: {
|
|
4088
|
+
type: "string",
|
|
4089
|
+
minLength: 1,
|
|
4090
|
+
maxLength: 40,
|
|
4091
|
+
},
|
|
4092
|
+
},
|
|
4093
|
+
},
|
|
4094
|
+
terminology: {
|
|
4095
|
+
type: "array",
|
|
4096
|
+
maxItems: 20,
|
|
4097
|
+
items: {
|
|
4098
|
+
type: "object",
|
|
4099
|
+
additionalProperties: false,
|
|
4100
|
+
required: ["system", "editionVersion", "licenseApproved"],
|
|
4101
|
+
properties: {
|
|
4102
|
+
system: {
|
|
4103
|
+
type: "string",
|
|
4104
|
+
enum: [
|
|
4105
|
+
"ICD-10-CM",
|
|
4106
|
+
"ICD-10-PCS",
|
|
4107
|
+
"CPT",
|
|
4108
|
+
"HCPCS",
|
|
4109
|
+
"NDC",
|
|
4110
|
+
"CDT",
|
|
4111
|
+
"REVENUE_CODE",
|
|
4112
|
+
"DRG",
|
|
4113
|
+
"MODIFIERS",
|
|
4114
|
+
"OTHER",
|
|
4115
|
+
],
|
|
4116
|
+
},
|
|
4117
|
+
editionVersion: {
|
|
4118
|
+
type: "string",
|
|
4119
|
+
minLength: 1,
|
|
4120
|
+
maxLength: 40,
|
|
4121
|
+
},
|
|
4122
|
+
licenseApproved: {
|
|
4123
|
+
type: "boolean",
|
|
4124
|
+
},
|
|
4125
|
+
},
|
|
4126
|
+
},
|
|
4127
|
+
},
|
|
4128
|
+
rules: {
|
|
4129
|
+
type: "array",
|
|
4130
|
+
maxItems: 30,
|
|
4131
|
+
items: {
|
|
4132
|
+
type: "object",
|
|
4133
|
+
additionalProperties: false,
|
|
4134
|
+
required: ["ruleId", "ruleVersion"],
|
|
4135
|
+
properties: {
|
|
4136
|
+
ruleId: {
|
|
4137
|
+
type: "string",
|
|
4138
|
+
minLength: 1,
|
|
4139
|
+
maxLength: 120,
|
|
4140
|
+
},
|
|
4141
|
+
ruleVersion: {
|
|
4142
|
+
type: "string",
|
|
4143
|
+
minLength: 1,
|
|
4144
|
+
maxLength: 40,
|
|
4145
|
+
},
|
|
4146
|
+
},
|
|
4147
|
+
},
|
|
4148
|
+
},
|
|
4149
|
+
retrievalCorpus: {
|
|
4150
|
+
type: "object",
|
|
4151
|
+
additionalProperties: false,
|
|
4152
|
+
properties: {
|
|
4153
|
+
corpusId: {
|
|
4154
|
+
type: "string",
|
|
4155
|
+
minLength: 1,
|
|
4156
|
+
maxLength: 120,
|
|
4157
|
+
},
|
|
4158
|
+
corpusVersion: {
|
|
4159
|
+
type: "string",
|
|
4160
|
+
minLength: 1,
|
|
4161
|
+
maxLength: 120,
|
|
4162
|
+
},
|
|
4163
|
+
},
|
|
4164
|
+
},
|
|
4165
|
+
generatedAt: {
|
|
4166
|
+
type: "string",
|
|
4167
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$",
|
|
4168
|
+
format: "date-time",
|
|
4169
|
+
maxLength: 64,
|
|
4170
|
+
},
|
|
4171
|
+
},
|
|
4172
|
+
},
|
|
4173
|
+
reviewerAction: {
|
|
4174
|
+
$ref: "coding-reviewer-action.schema.json",
|
|
4175
|
+
},
|
|
4176
|
+
extensions: {
|
|
4177
|
+
type: "array",
|
|
4178
|
+
maxItems: 25,
|
|
4179
|
+
items: {
|
|
4180
|
+
$ref: "coding-extension.schema.json",
|
|
4181
|
+
},
|
|
4182
|
+
},
|
|
4183
|
+
},
|
|
4184
|
+
if: {
|
|
4185
|
+
properties: {
|
|
4186
|
+
disposition: {
|
|
4187
|
+
const: "review_required",
|
|
4188
|
+
},
|
|
4189
|
+
},
|
|
4190
|
+
required: ["disposition"],
|
|
4191
|
+
},
|
|
4192
|
+
then: {
|
|
4193
|
+
properties: {
|
|
4194
|
+
lineDecisions: {
|
|
4195
|
+
minItems: 1,
|
|
4196
|
+
},
|
|
4197
|
+
provenance: {
|
|
4198
|
+
properties: {
|
|
4199
|
+
terminology: {
|
|
4200
|
+
minItems: 1,
|
|
4201
|
+
},
|
|
4202
|
+
rules: {
|
|
4203
|
+
minItems: 1,
|
|
4204
|
+
},
|
|
4205
|
+
},
|
|
4206
|
+
},
|
|
4207
|
+
},
|
|
4208
|
+
},
|
|
4209
|
+
else: {
|
|
4210
|
+
properties: {
|
|
4211
|
+
lineDecisions: {
|
|
4212
|
+
maxItems: 0,
|
|
4213
|
+
},
|
|
4214
|
+
},
|
|
4215
|
+
},
|
|
4216
|
+
};
|
|
4217
|
+
// --------------------------------------------------------------------
|
|
21
4218
|
// RcmSupportingReference (schema 1.0.0, wire rcm-supporting-reference-v1)
|
|
22
4219
|
// --------------------------------------------------------------------
|
|
23
4220
|
export const rcmSupportingReferenceSchema = z
|
|
@@ -48,6 +4245,8 @@ export const rcmSupportingReferenceSchema = z
|
|
|
48
4245
|
export function rcmSupportingReferenceValidationError(value) {
|
|
49
4246
|
if (!isRecord(value))
|
|
50
4247
|
return "reference";
|
|
4248
|
+
if (!["referenceId", "title", "excerpt"].every((key) => key in value))
|
|
4249
|
+
return "reference_keys";
|
|
51
4250
|
if (!Object.keys(value).every((key) => [
|
|
52
4251
|
"referenceId",
|
|
53
4252
|
"documentId",
|
|
@@ -61,8 +4260,7 @@ export function rcmSupportingReferenceValidationError(value) {
|
|
|
61
4260
|
"coveredPayerProgram",
|
|
62
4261
|
"sourceUrl",
|
|
63
4262
|
"humanReviewRequired",
|
|
64
|
-
].includes(key))
|
|
65
|
-
!["referenceId", "title", "excerpt"].every((key) => key in value))
|
|
4263
|
+
].includes(key)))
|
|
66
4264
|
return "reference_keys";
|
|
67
4265
|
const value_referenceId = value["referenceId"];
|
|
68
4266
|
if (typeof value_referenceId !== "string" ||
|
|
@@ -231,6 +4429,8 @@ export const rcmCodingInputSchema = z
|
|
|
231
4429
|
export function rcmCodingInputValidationError(value) {
|
|
232
4430
|
if (!isRecord(value))
|
|
233
4431
|
return "coding_input";
|
|
4432
|
+
if (!["encounterId", "diagnosisNarrative"].every((key) => key in value))
|
|
4433
|
+
return "coding_input_keys";
|
|
234
4434
|
if (!Object.keys(value).every((key) => [
|
|
235
4435
|
"encounterId",
|
|
236
4436
|
"diagnosisNarrative",
|
|
@@ -239,8 +4439,7 @@ export function rcmCodingInputValidationError(value) {
|
|
|
239
4439
|
"placeOfService",
|
|
240
4440
|
"claimContext",
|
|
241
4441
|
"supportingReferences",
|
|
242
|
-
].includes(key))
|
|
243
|
-
!["encounterId", "diagnosisNarrative"].every((key) => key in value))
|
|
4442
|
+
].includes(key)))
|
|
244
4443
|
return "coding_input_keys";
|
|
245
4444
|
const value_encounterId = value["encounterId"];
|
|
246
4445
|
if (typeof value_encounterId !== "string" ||
|
|
@@ -307,9 +4506,9 @@ export function rcmCodingInputValidationError(value) {
|
|
|
307
4506
|
value_supportingReferences.length > 10)
|
|
308
4507
|
return "supporting_references";
|
|
309
4508
|
for (const item of value_supportingReferences) {
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
return
|
|
4509
|
+
const itemRefError = rcmSupportingReferenceValidationError(item);
|
|
4510
|
+
if (itemRefError !== null)
|
|
4511
|
+
return itemRefError;
|
|
313
4512
|
}
|
|
314
4513
|
}
|
|
315
4514
|
return null;
|
|
@@ -453,20 +4652,21 @@ export const rcmCodingOutputSchema = z
|
|
|
453
4652
|
export function rcmCodingOutputValidationError(value, options) {
|
|
454
4653
|
if (!isRecord(value))
|
|
455
4654
|
return "not_object";
|
|
4655
|
+
if (![
|
|
4656
|
+
"disposition",
|
|
4657
|
+
"humanReviewRequired",
|
|
4658
|
+
"recommendations",
|
|
4659
|
+
"documentationGaps",
|
|
4660
|
+
"rationale",
|
|
4661
|
+
].every((key) => key in value))
|
|
4662
|
+
return "top_level_keys";
|
|
456
4663
|
if (!Object.keys(value).every((key) => [
|
|
457
4664
|
"disposition",
|
|
458
4665
|
"humanReviewRequired",
|
|
459
4666
|
"rationale",
|
|
460
4667
|
"recommendations",
|
|
461
4668
|
"documentationGaps",
|
|
462
|
-
].includes(key))
|
|
463
|
-
![
|
|
464
|
-
"disposition",
|
|
465
|
-
"humanReviewRequired",
|
|
466
|
-
"recommendations",
|
|
467
|
-
"documentationGaps",
|
|
468
|
-
"rationale",
|
|
469
|
-
].every((key) => key in value))
|
|
4669
|
+
].includes(key)))
|
|
470
4670
|
return "top_level_keys";
|
|
471
4671
|
const value_disposition = value["disposition"];
|
|
472
4672
|
if (typeof value_disposition !== "string" ||
|
|
@@ -489,14 +4689,15 @@ export function rcmCodingOutputValidationError(value, options) {
|
|
|
489
4689
|
for (const item of value_recommendations) {
|
|
490
4690
|
if (!isRecord(item))
|
|
491
4691
|
return "recommendation_keys";
|
|
4692
|
+
if (!["code", "codeSystem", "confidence", "rationale", "evidenceIds"].every((key) => key in item))
|
|
4693
|
+
return "recommendation_keys";
|
|
492
4694
|
if (!Object.keys(item).every((key) => [
|
|
493
4695
|
"code",
|
|
494
4696
|
"codeSystem",
|
|
495
4697
|
"confidence",
|
|
496
4698
|
"rationale",
|
|
497
4699
|
"evidenceIds",
|
|
498
|
-
].includes(key))
|
|
499
|
-
!["code", "codeSystem", "confidence", "rationale", "evidenceIds"].every((key) => key in item))
|
|
4700
|
+
].includes(key)))
|
|
500
4701
|
return "recommendation_keys";
|
|
501
4702
|
const item_code = item["code"];
|
|
502
4703
|
if (typeof item_code !== "string" ||
|
|
@@ -724,12 +4925,15 @@ export const rcmModelPromptSchema = z
|
|
|
724
4925
|
export function rcmModelPromptValidationError(value) {
|
|
725
4926
|
if (!isRecord(value))
|
|
726
4927
|
return "model_prompt";
|
|
727
|
-
if (!
|
|
728
|
-
|
|
4928
|
+
if (!["encounter", "supportingReferences"].every((key) => key in value))
|
|
4929
|
+
return "model_prompt_keys";
|
|
4930
|
+
if (!Object.keys(value).every((key) => ["encounter", "supportingReferences"].includes(key)))
|
|
729
4931
|
return "model_prompt_keys";
|
|
730
4932
|
const value_encounter = value["encounter"];
|
|
731
4933
|
if (!isRecord(value_encounter))
|
|
732
4934
|
return "encounter";
|
|
4935
|
+
if (!["encounterId", "diagnosisNarrative"].every((key) => key in value_encounter))
|
|
4936
|
+
return "encounter_keys";
|
|
733
4937
|
if (!Object.keys(value_encounter).every((key) => [
|
|
734
4938
|
"encounterId",
|
|
735
4939
|
"diagnosisNarrative",
|
|
@@ -737,8 +4941,7 @@ export function rcmModelPromptValidationError(value) {
|
|
|
737
4941
|
"serviceDate",
|
|
738
4942
|
"placeOfService",
|
|
739
4943
|
"claimContext",
|
|
740
|
-
].includes(key))
|
|
741
|
-
!["encounterId", "diagnosisNarrative"].every((key) => key in value_encounter))
|
|
4944
|
+
].includes(key)))
|
|
742
4945
|
return "encounter_keys";
|
|
743
4946
|
const value_encounter_encounterId = value_encounter["encounterId"];
|
|
744
4947
|
if (typeof value_encounter_encounterId !== "string" ||
|
|
@@ -804,9 +5007,9 @@ export function rcmModelPromptValidationError(value) {
|
|
|
804
5007
|
value_supportingReferences.length > 5)
|
|
805
5008
|
return "model_prompt_references";
|
|
806
5009
|
for (const item of value_supportingReferences) {
|
|
807
|
-
const
|
|
808
|
-
if (
|
|
809
|
-
return
|
|
5010
|
+
const itemRefError = rcmSupportingReferenceValidationError(item);
|
|
5011
|
+
if (itemRefError !== null)
|
|
5012
|
+
return itemRefError;
|
|
810
5013
|
}
|
|
811
5014
|
return null;
|
|
812
5015
|
}
|
|
@@ -901,6 +5104,8 @@ export const rcmRetrievalMetadataSchema = z
|
|
|
901
5104
|
export function rcmRetrievalMetadataValidationError(value) {
|
|
902
5105
|
if (!isRecord(value))
|
|
903
5106
|
return "retrieval_metadata";
|
|
5107
|
+
if (!["corpusId", "corpusVersion", "outcome", "latencyMs", "references"].every((key) => key in value))
|
|
5108
|
+
return "retrieval_metadata_keys";
|
|
904
5109
|
if (!Object.keys(value).every((key) => [
|
|
905
5110
|
"corpusId",
|
|
906
5111
|
"corpusVersion",
|
|
@@ -909,8 +5114,7 @@ export function rcmRetrievalMetadataValidationError(value) {
|
|
|
909
5114
|
"knowledgeBaseId",
|
|
910
5115
|
"tenantId",
|
|
911
5116
|
"references",
|
|
912
|
-
].includes(key))
|
|
913
|
-
!["corpusId", "corpusVersion", "outcome", "latencyMs", "references"].every((key) => key in value))
|
|
5117
|
+
].includes(key)))
|
|
914
5118
|
return "retrieval_metadata_keys";
|
|
915
5119
|
const value_corpusId = value["corpusId"];
|
|
916
5120
|
if (typeof value_corpusId !== "string" ||
|
|
@@ -947,9 +5151,9 @@ export function rcmRetrievalMetadataValidationError(value) {
|
|
|
947
5151
|
if (!Array.isArray(value_references))
|
|
948
5152
|
return "retrieval_references";
|
|
949
5153
|
for (const item of value_references) {
|
|
950
|
-
const
|
|
951
|
-
if (
|
|
952
|
-
return
|
|
5154
|
+
const itemRefError = rcmSupportingReferenceValidationError(item);
|
|
5155
|
+
if (itemRefError !== null)
|
|
5156
|
+
return itemRefError;
|
|
953
5157
|
}
|
|
954
5158
|
return null;
|
|
955
5159
|
}
|
|
@@ -1060,6 +5264,8 @@ export const rcmRuntimeEventSchema = z
|
|
|
1060
5264
|
export function rcmRuntimeEventValidationError(value) {
|
|
1061
5265
|
if (!isRecord(value))
|
|
1062
5266
|
return "runtime_event";
|
|
5267
|
+
if (!["type", "outcome", "reason", "occurredAt", "workflowId"].every((key) => key in value))
|
|
5268
|
+
return "runtime_event_keys";
|
|
1063
5269
|
if (!Object.keys(value).every((key) => [
|
|
1064
5270
|
"type",
|
|
1065
5271
|
"outcome",
|
|
@@ -1068,8 +5274,7 @@ export function rcmRuntimeEventValidationError(value) {
|
|
|
1068
5274
|
"workflowId",
|
|
1069
5275
|
"guardrail",
|
|
1070
5276
|
"retrieval",
|
|
1071
|
-
].includes(key))
|
|
1072
|
-
!["type", "outcome", "reason", "occurredAt", "workflowId"].every((key) => key in value))
|
|
5277
|
+
].includes(key)))
|
|
1073
5278
|
return "runtime_event_keys";
|
|
1074
5279
|
const value_type = value["type"];
|
|
1075
5280
|
if (typeof value_type !== "string" ||
|
|
@@ -1119,8 +5324,9 @@ export function rcmRuntimeEventValidationError(value) {
|
|
|
1119
5324
|
for (const item of value_guardrail_actions) {
|
|
1120
5325
|
if (!isRecord(item))
|
|
1121
5326
|
return "runtime_event_guardrail_action";
|
|
1122
|
-
if (!
|
|
1123
|
-
|
|
5327
|
+
if (!["scope", "policyType", "rule", "action"].every((key) => key in item))
|
|
5328
|
+
return "runtime_event_guardrail_action_keys";
|
|
5329
|
+
if (!Object.keys(item).every((key) => ["scope", "policyType", "rule", "action"].includes(key)))
|
|
1124
5330
|
return "runtime_event_guardrail_action_keys";
|
|
1125
5331
|
const item_scope = item["scope"];
|
|
1126
5332
|
if (typeof item_scope !== "string" || item_scope.length > 64)
|
|
@@ -1141,6 +5347,15 @@ export function rcmRuntimeEventValidationError(value) {
|
|
|
1141
5347
|
const value_retrieval = value["retrieval"];
|
|
1142
5348
|
if (!isRecord(value_retrieval))
|
|
1143
5349
|
return "runtime_event_retrieval";
|
|
5350
|
+
if (![
|
|
5351
|
+
"corpusId",
|
|
5352
|
+
"corpusVersion",
|
|
5353
|
+
"outcome",
|
|
5354
|
+
"referenceCount",
|
|
5355
|
+
"latencyMs",
|
|
5356
|
+
"references",
|
|
5357
|
+
].every((key) => key in value_retrieval))
|
|
5358
|
+
return "runtime_event_retrieval_keys";
|
|
1144
5359
|
if (!Object.keys(value_retrieval).every((key) => [
|
|
1145
5360
|
"corpusId",
|
|
1146
5361
|
"corpusVersion",
|
|
@@ -1148,15 +5363,7 @@ export function rcmRuntimeEventValidationError(value) {
|
|
|
1148
5363
|
"referenceCount",
|
|
1149
5364
|
"latencyMs",
|
|
1150
5365
|
"references",
|
|
1151
|
-
].includes(key))
|
|
1152
|
-
![
|
|
1153
|
-
"corpusId",
|
|
1154
|
-
"corpusVersion",
|
|
1155
|
-
"outcome",
|
|
1156
|
-
"referenceCount",
|
|
1157
|
-
"latencyMs",
|
|
1158
|
-
"references",
|
|
1159
|
-
].every((key) => key in value_retrieval))
|
|
5366
|
+
].includes(key)))
|
|
1160
5367
|
return "runtime_event_retrieval_keys";
|
|
1161
5368
|
const value_retrieval_corpusId = value_retrieval["corpusId"];
|
|
1162
5369
|
if (typeof value_retrieval_corpusId !== "string" ||
|
|
@@ -1190,8 +5397,9 @@ export function rcmRuntimeEventValidationError(value) {
|
|
|
1190
5397
|
for (const item of value_retrieval_references) {
|
|
1191
5398
|
if (!isRecord(item))
|
|
1192
5399
|
return "runtime_event_retrieval_reference";
|
|
1193
|
-
if (!
|
|
1194
|
-
|
|
5400
|
+
if (!["referenceId", "documentId", "version"].every((key) => key in item))
|
|
5401
|
+
return "runtime_event_retrieval_reference_keys";
|
|
5402
|
+
if (!Object.keys(item).every((key) => ["referenceId", "documentId", "version"].includes(key)))
|
|
1195
5403
|
return "runtime_event_retrieval_reference_keys";
|
|
1196
5404
|
const item_referenceId = item["referenceId"];
|
|
1197
5405
|
if (typeof item_referenceId !== "string" ||
|
|
@@ -1382,6 +5590,16 @@ export const rcmWorkflowCatalogSchema = z
|
|
|
1382
5590
|
export function rcmWorkflowCatalogValidationError(value) {
|
|
1383
5591
|
if (!isRecord(value))
|
|
1384
5592
|
return "workflow_catalog";
|
|
5593
|
+
if (![
|
|
5594
|
+
"id",
|
|
5595
|
+
"name",
|
|
5596
|
+
"description",
|
|
5597
|
+
"environments",
|
|
5598
|
+
"modelPolicy",
|
|
5599
|
+
"humanReviewPolicy",
|
|
5600
|
+
"outputSchemaVersion",
|
|
5601
|
+
].every((key) => key in value))
|
|
5602
|
+
return "workflow_catalog_keys";
|
|
1385
5603
|
if (!Object.keys(value).every((key) => [
|
|
1386
5604
|
"id",
|
|
1387
5605
|
"name",
|
|
@@ -1390,16 +5608,7 @@ export function rcmWorkflowCatalogValidationError(value) {
|
|
|
1390
5608
|
"modelPolicy",
|
|
1391
5609
|
"humanReviewPolicy",
|
|
1392
5610
|
"outputSchemaVersion",
|
|
1393
|
-
].includes(key))
|
|
1394
|
-
![
|
|
1395
|
-
"id",
|
|
1396
|
-
"name",
|
|
1397
|
-
"description",
|
|
1398
|
-
"environments",
|
|
1399
|
-
"modelPolicy",
|
|
1400
|
-
"humanReviewPolicy",
|
|
1401
|
-
"outputSchemaVersion",
|
|
1402
|
-
].every((key) => key in value))
|
|
5611
|
+
].includes(key)))
|
|
1403
5612
|
return "workflow_catalog_keys";
|
|
1404
5613
|
const value_id = value["id"];
|
|
1405
5614
|
if (typeof value_id !== "string" ||
|
|
@@ -1426,6 +5635,15 @@ export function rcmWorkflowCatalogValidationError(value) {
|
|
|
1426
5635
|
const value_modelPolicy = value["modelPolicy"];
|
|
1427
5636
|
if (!isRecord(value_modelPolicy))
|
|
1428
5637
|
return "model_policy";
|
|
5638
|
+
if (![
|
|
5639
|
+
"policyId",
|
|
5640
|
+
"inferencePath",
|
|
5641
|
+
"maxNewTokens",
|
|
5642
|
+
"temperature",
|
|
5643
|
+
"outputSchemaVersion",
|
|
5644
|
+
"requireHumanReview",
|
|
5645
|
+
].every((key) => key in value_modelPolicy))
|
|
5646
|
+
return "model_policy_keys";
|
|
1429
5647
|
if (!Object.keys(value_modelPolicy).every((key) => [
|
|
1430
5648
|
"policyId",
|
|
1431
5649
|
"inferencePath",
|
|
@@ -1433,15 +5651,7 @@ export function rcmWorkflowCatalogValidationError(value) {
|
|
|
1433
5651
|
"temperature",
|
|
1434
5652
|
"outputSchemaVersion",
|
|
1435
5653
|
"requireHumanReview",
|
|
1436
|
-
].includes(key))
|
|
1437
|
-
![
|
|
1438
|
-
"policyId",
|
|
1439
|
-
"inferencePath",
|
|
1440
|
-
"maxNewTokens",
|
|
1441
|
-
"temperature",
|
|
1442
|
-
"outputSchemaVersion",
|
|
1443
|
-
"requireHumanReview",
|
|
1444
|
-
].every((key) => key in value_modelPolicy))
|
|
5654
|
+
].includes(key)))
|
|
1445
5655
|
return "model_policy_keys";
|
|
1446
5656
|
const value_modelPolicy_policyId = value_modelPolicy["policyId"];
|
|
1447
5657
|
if (typeof value_modelPolicy_policyId !== "string" ||
|
|
@@ -1475,8 +5685,9 @@ export function rcmWorkflowCatalogValidationError(value) {
|
|
|
1475
5685
|
const value_humanReviewPolicy = value["humanReviewPolicy"];
|
|
1476
5686
|
if (!isRecord(value_humanReviewPolicy))
|
|
1477
5687
|
return "human_review_policy";
|
|
1478
|
-
if (!
|
|
1479
|
-
|
|
5688
|
+
if (!["policyId", "humanReviewRequired"].every((key) => key in value_humanReviewPolicy))
|
|
5689
|
+
return "human_review_policy_keys";
|
|
5690
|
+
if (!Object.keys(value_humanReviewPolicy).every((key) => ["policyId", "humanReviewRequired"].includes(key)))
|
|
1480
5691
|
return "human_review_policy_keys";
|
|
1481
5692
|
const value_humanReviewPolicy_policyId = value_humanReviewPolicy["policyId"];
|
|
1482
5693
|
if (typeof value_humanReviewPolicy_policyId !== "string" ||
|