Path:
schemas/protocol.schema.json
Lines:
696
Non-empty lines:
696
Non-empty lines covered with requirements:
183 / 696 (26.3%)
Functions:
0
Functions covered by requirements:
0 / 0 (0.0%)
1
{2
"$schema": "https://json-schema.org/draft/2020-12/schema",
3
"$id": "urn:syntol:extractor-format:schema:protocol:2",
4
"title": "Extractor protocol",
5
"description": "Hardware-independent laboratory protocol for a magnetic-particle extractor",
6
"$comment": "Semantic validation must additionally check uniqueness of local IDs; existence and type of every local and catalog reference; referenced definition revision; availability of the referenced labware at each step, including replacements on a shared seat; plate and sleeve membership in the selected device model; step preconditions; component volume totals; and parameter ranges from device and labware definitions.",
7
"type": "object",
8
"required": [
9
"schema",
10
"revision",
11
"uid",
12
"title",
13
"description",
14
"created_at",
15
"modified_at",
16
"device",
17
"required_capabilities",
18
"components",
19
"labware",
20
"steps",
21
"heater_final_state"
22
],
23
"properties": {
24
"schema": {
25
"type": "object",
26
"required": [ "name", "revision" ],
27
"properties": {
28
"name": {
29
"const": "syntol.extractor.protocol"
30
},
31
"revision": {
32
"const": 2
33
}
34
},
35
"additionalProperties": false
36
},
37
"revision": {
38
"description": "Revision of this particular protocol",
39
"type": "integer",
40
"minimum": 1
41
},
42
"uid": {
43
"description": "Stable global identifier of the protocol across revisions",
44
"$ref": "#/$defs/uuid_v4"
45
},
46
"title": {
47
"type": "string",
48
"maxLength": 200,
49
"minLength": 1
50
},
51
"description": {
52
"type": "string",
53
"maxLength": 2000,
54
"minLength": 1
55
},
56
"created_at": {
57
"type": "string",
58
"format": "date-time"
59
},
60
"modified_at": {
61
"type": "string",
62
"format": "date-time"
63
},
64
"instructions": {
65
"type": "object",
66
"properties": {
67
"before_run": {
68
"type": "string",
69
"minLength": 1
70
},
71
"after_run": {
72
"type": "string",
73
"minLength": 1
74
}
75
},
76
"additionalProperties": false
77
},
78
"device": {
79
"description": "Reference to the compatible device-model definition, not to a device instance or serial number",
80
"$ref": "#/$defs/definition_reference"
81
},
82
"required_capabilities": {
83
"type": "array",
84
"minItems": 1,
85
"uniqueItems": true,
86
"items": {
87
"$ref": "#/$defs/device_capability"
88
}
89
},
90
"components": {
91
"description": "Definitions of the typical well-content components used by this protocol",
92
"type": "array",
93
"minItems": 1,
94
"items": {
95
"$ref": "#/$defs/component"
96
}
97
},
98
"labware": {
99
"description": "Protocol-local labware instances and their layout",
100
"type": "array",
101
"minItems": 1,
102
"items": {
103
"oneOf": [
104
{
105
"$ref": "#/$defs/plate_instance"
106
},
107
{
108
"$ref": "#/$defs/sleeve_comb_instance"
109
}
110
]
111
}
112
},
113
"steps": {
114
"description": "Ordered protocol steps",
115
"type": "array",
116
"minItems": 1,
117
"items": {
118
"oneOf": [
119
{
120
"$ref": "#/$defs/collect_sleeves_step"
121
},
122
{
123
"$ref": "#/$defs/release_sleeves_step"
124
},
125
{
126
"$ref": "#/$defs/set_temperature_step"
127
},
128
{
129
"$ref": "#/$defs/wait_temperature_step"
130
},
131
{
132
"$ref": "#/$defs/mix_step"
133
},
134
{
135
"$ref": "#/$defs/collect_beads_step"
136
},
137
{
138
"$ref": "#/$defs/release_beads_step"
139
}
140
]
141
}
142
},
143
"heater_final_state": {
144
"description": "Required state of all heaters after the protocol finishes or aborts",
145
"const": "off"
146
},
147
"extensions": {
148
"$ref": "#/$defs/extensions"
149
}
150
},
151
"additionalProperties": false,
152
"$defs": {
153
"local_id": {
154
"type": "string",
155
"pattern": "^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$",
156
"maxLength": 100
157
},
158
"uuid_v4": {
159
"type": "string",
160
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
161
"format": "uuid"
162
},
163
"definition_reference": {
164
"type": "object",
165
"required": [ "uid", "revision" ],
166
"properties": {
167
"uid": {
168
"$ref": "#/$defs/uuid_v4"
169
},
170
"revision": {
171
"type": "integer",
172
"minimum": 1
173
}
174
},
175
"additionalProperties": false
176
},
177
"extensions": {
178
"description": "Namespaced non-standard metadata ignored unless explicitly supported",
179
"type": "object",
180
"propertyNames": {
181
"pattern": "^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)+$"
182
},
183
"additionalProperties": true
184
},
185
"device_capability": {
186
"enum": [
187
"motion_absolute",
188
"homing",
189
"mixing_time",
190
"mixing_cycles",
191
"motion_configuration",
192
"temperature_control",
193
"temperature_wait",
194
"sleeves_detection",
195
"offsets_configurations",
196
"plate_detection",
197
"uv_sterilization",
198
"status_leds",
199
"notify_beeper",
200
"safety_interlocks",
201
"power_management"
202
]
203
},
204
"component": {
205
"type": "object",
206
"required": [ "id", "title" ],
207
"properties": {
208
"id": {
209
"$ref": "#/$defs/uuid_v4"
210
},
211
"title": {
212
"type": "string",
213
"maxLength": 200,
214
"minLength": 1
215
},
216
"role": {
217
"description": "Optional protocol-local classification used for reporting and editing",
218
"$ref": "#/$defs/local_id"
219
},
220
"color": {
221
"description": "Editor-only hint; it has no execution semantics",
222
"type": "string",
223
"pattern": "^#[0-9A-Fa-f]{6}$"
224
},
225
"extensions": {
226
"$ref": "#/$defs/extensions"
227
}
228
},
229
"additionalProperties": false
230
},
231
"well_component": {
232
"type": "object",
233
"required": [ "component_id", "volume_ul" ],
234
"properties": {
235
"component_id": {
236
"$ref": "#/$defs/uuid_v4"
237
},
238
"volume_ul": {
239
"description": "Volume in one typical well, in microliters",
240
"type": "number",
241
"exclusiveMinimum": 0
242
}
243
},
244
"additionalProperties": false
245
},
246
"plate_purpose": {
247
"enum": [
248
"sample_input",
249
"lysis",
250
"wash",
251
"elution",
252
"waste",
253
"intermediate"
254
]
255
},
256
"plate_instance": {
257
"type": "object",
258
"required": [
259
"id",
260
"kind",
261
"title",
262
"purpose",
263
"seat",
264
"model",
265
"well_content"
266
],
267
"properties": {
268
"id": {
269
"$ref": "#/$defs/local_id"
270
},
271
"kind": {
272
"const": "plate"
273
},
274
"title": {
275
"type": "string",
276
"maxLength": 200,
277
"minLength": 1
278
},
279
"purpose": {
280
"$ref": "#/$defs/plate_purpose"
281
},
282
"seat": {
283
"type": "integer",
284
"minimum": 1
285
},
286
"model": {
287
"$ref": "#/$defs/definition_reference"
288
},
289
"well_content": {
290
"description": "Composition of one typical working well; it does not imply that every well is occupied",
291
"type": "array",
292
"minItems": 1,
293
"items": {
294
"$ref": "#/$defs/well_component"
295
}
296
},
297
"extensions": {
298
"$ref": "#/$defs/extensions"
299
}
300
},
301
"additionalProperties": false
302
},
303
"sleeve_comb_instance": {
304
"type": "object",
305
"required": [ "id", "kind", "title", "purpose", "seat", "model" ],
306
"properties": {
307
"id": {
308
"$ref": "#/$defs/local_id"
309
},
310
"kind": {
311
"const": "sleeve_comb"
312
},
313
"title": {
314
"type": "string",
315
"maxLength": 200,
316
"minLength": 1
317
},
318
"purpose": {
319
"const": "sleeve_storage"
320
},
321
"seat": {
322
"type": "integer",
323
"minimum": 1
324
},
325
"model": {
326
"$ref": "#/$defs/definition_reference"
327
},
328
"extensions": {
329
"$ref": "#/$defs/extensions"
330
}
331
},
332
"additionalProperties": false
333
},
334
"error_policy": {
335
"enum": [ "abort", "operator_decision" ]
336
},
337
"position": {
338
"oneOf": [
339
{
340
"type": "object",
341
"required": [ "reference" ],
342
"properties": {
343
"reference": {
344
"enum": [ "above_liquid", "liquid_surface", "liquid_middle" ]
345
}
346
},
347
"additionalProperties": false
348
},
349
{
350
"type": "object",
351
"required": [ "reference", "offset_mm" ],
352
"properties": {
353
"reference": {
354
"const": "well_bottom_offset"
355
},
356
"offset_mm": {
357
"type": "number",
358
"minimum": 0
359
}
360
},
361
"additionalProperties": false
362
}
363
]
364
},
365
"collect_sleeves_step": {
366
"type": "object",
367
"required": [ "id", "kind", "title", "labware_id", "on_error" ],
368
"properties": {
369
"id": {
370
"$ref": "#/$defs/uuid_v4"
371
},
372
"kind": {
373
"const": "collect_sleeves"
374
},
375
"title": {
376
"type": "string",
377
"maxLength": 200,
378
"minLength": 1
379
},
380
"labware_id": {
381
"$ref": "#/$defs/local_id"
382
},
383
"on_error": {
384
"$ref": "#/$defs/error_policy"
385
},
386
"extensions": {
387
"$ref": "#/$defs/extensions"
388
}
389
},
390
"additionalProperties": false
391
},
392
"release_sleeves_step": {
393
"type": "object",
394
"required": [ "id", "kind", "title", "labware_id", "on_error" ],
395
"properties": {
396
"id": {
397
"$ref": "#/$defs/uuid_v4"
398
},
399
"kind": {
400
"const": "release_sleeves"
401
},
402
"title": {
403
"type": "string",
404
"maxLength": 200,
405
"minLength": 1
406
},
407
"labware_id": {
408
"$ref": "#/$defs/local_id"
409
},
410
"on_error": {
411
"$ref": "#/$defs/error_policy"
412
},
413
"extensions": {
414
"$ref": "#/$defs/extensions"
415
}
416
},
417
"additionalProperties": false
418
},
419
"set_temperature_step": {
420
"type": "object",
421
"required": [
422
"id",
423
"kind",
424
"title",
425
"labware_id",
426
"target_celsius",
427
"on_error"
428
],
429
"properties": {
430
"id": {
431
"$ref": "#/$defs/uuid_v4"
432
},
433
"kind": {
434
"const": "set_temperature"
435
},
436
"title": {
437
"type": "string",
438
"maxLength": 200,
439
"minLength": 1
440
},
441
"labware_id": {
442
"$ref": "#/$defs/local_id"
443
},
444
"target_celsius": {
445
"type": "number"
446
},
447
"on_error": {
448
"$ref": "#/$defs/error_policy"
449
},
450
"extensions": {
451
"$ref": "#/$defs/extensions"
452
}
453
},
454
"additionalProperties": false
455
},
456
"wait_temperature_step": {
457
"type": "object",
458
"required": [
459
"id",
460
"kind",
461
"title",
462
"labware_id",
463
"target_celsius",
464
"tolerance_celsius",
465
"timeout_s",
466
"on_error"
467
],
468
"properties": {
469
"id": {
470
"$ref": "#/$defs/uuid_v4"
471
},
472
"kind": {
473
"const": "wait_temperature"
474
},
475
"title": {
476
"type": "string",
477
"maxLength": 200,
478
"minLength": 1
479
},
480
"labware_id": {
481
"$ref": "#/$defs/local_id"
482
},
483
"target_celsius": {
484
"type": "number"
485
},
486
"tolerance_celsius": {
487
"type": "number",
488
"exclusiveMinimum": 0
489
},
490
"timeout_s": {
491
"type": "number",
492
"exclusiveMinimum": 0
493
},
494
"on_error": {
495
"$ref": "#/$defs/error_policy"
496
},
497
"extensions": {
498
"$ref": "#/$defs/extensions"
499
}
500
},
501
"additionalProperties": false
502
},
503
"mix_purpose": {
504
"enum": [ "lysis", "wash", "drying", "elution", "custom" ]
505
},
506
"mix_stage": {
507
"type": "object",
508
"oneOf": [
509
{
510
"not": {
511
"required": [ "cycles" ]
512
},
513
"required": [ "duration_s" ]
514
},
515
{
516
"not": {
517
"required": [ "duration_s" ]
518
},
519
"required": [ "cycles" ]
520
}
521
],
522
"required": [ "start_position", "amplitude_mm", "speed_mm_min" ],
523
"properties": {
524
"start_position": {
525
"$ref": "#/$defs/position"
526
},
527
"amplitude_mm": {
528
"type": "number",
529
"exclusiveMinimum": 0
530
},
531
"speed_mm_min": {
532
"type": "number",
533
"exclusiveMinimum": 0
534
},
535
"duration_s": {
536
"type": "number",
537
"exclusiveMinimum": 0
538
},
539
"cycles": {
540
"type": "integer",
541
"minimum": 1
542
},
543
"pause": {
544
"type": "object",
545
"required": [ "position", "duration_s" ],
546
"properties": {
547
"position": {
548
"$ref": "#/$defs/position"
549
},
550
"duration_s": {
551
"type": "number",
552
"minimum": 0
553
}
554
},
555
"additionalProperties": false
556
}
557
},
558
"additionalProperties": false
559
},
560
"mix_step": {
561
"type": "object",
562
"required": [
563
"id",
564
"kind",
565
"title",
566
"purpose",
567
"labware_id",
568
"repeat_count",
569
"stages",
570
"on_error"
571
],
572
"properties": {
573
"id": {
574
"$ref": "#/$defs/uuid_v4"
575
},
576
"kind": {
577
"const": "mix"
578
},
579
"title": {
580
"type": "string",
581
"maxLength": 200,
582
"minLength": 1
583
},
584
"purpose": {
585
"$ref": "#/$defs/mix_purpose"
586
},
587
"labware_id": {
588
"$ref": "#/$defs/local_id"
589
},
590
"repeat_count": {
591
"type": "integer",
592
"minimum": 1
593
},
594
"stages": {
595
"type": "array",
596
"minItems": 1,
597
"items": {
598
"$ref": "#/$defs/mix_stage"
599
}
600
},
601
"on_error": {
602
"$ref": "#/$defs/error_policy"
603
},
604
"extensions": {
605
"$ref": "#/$defs/extensions"
606
}
607
},
608
"additionalProperties": false
609
},
610
"collect_beads_step": {
611
"type": "object",
612
"required": [
613
"id",
614
"kind",
615
"title",
616
"labware_id",
617
"collection_cycles",
618
"hold_duration_s",
619
"on_error"
620
],
621
"properties": {
622
"id": {
623
"$ref": "#/$defs/uuid_v4"
624
},
625
"kind": {
626
"const": "collect_beads"
627
},
628
"title": {
629
"type": "string",
630
"maxLength": 200,
631
"minLength": 1
632
},
633
"labware_id": {
634
"$ref": "#/$defs/local_id"
635
},
636
"collection_cycles": {
637
"type": "integer",
638
"minimum": 1
639
},
640
"hold_duration_s": {
641
"type": "number",
642
"exclusiveMinimum": 0
643
},
644
"on_error": {
645
"$ref": "#/$defs/error_policy"
646
},
647
"extensions": {
648
"$ref": "#/$defs/extensions"
649
}
650
},
651
"additionalProperties": false
652
},
653
"release_beads_step": {
654
"type": "object",
655
"required": [
656
"id",
657
"kind",
658
"title",
659
"labware_id",
660
"start_position",
661
"duration_s",
662
"on_error"
663
],
664
"properties": {
665
"id": {
666
"$ref": "#/$defs/uuid_v4"
667
},
668
"kind": {
669
"const": "release_beads"
670
},
671
"title": {
672
"type": "string",
673
"maxLength": 200,
674
"minLength": 1
675
},
676
"labware_id": {
677
"$ref": "#/$defs/local_id"
678
},
679
"start_position": {
680
"$ref": "#/$defs/position"
681
},
682
"duration_s": {
683
"type": "number",
684
"exclusiveMinimum": 0
685
},
686
"on_error": {
687
"$ref": "#/$defs/error_policy"
688
},
689
"extensions": {
690
"$ref": "#/$defs/extensions"
691
}
692
},
693
"additionalProperties": false
694
}
695
}
696
}