master
json 2,758 lines 63.1 KB
Raw
1 {
2 "$schema": "https://json-schema.org/draft/2020-12/schema",
3 "$id": "https://schemas.netdata.cloud/functions/topology/v1.json",
4 "title": "Netdata Topology Function Payload",
5 "description": "Production topology Function payload schema. This schema carries canonical topology facts for aggregation and UI rendering. It intentionally does not carry rollout-adapter reconstruction instructions.",
6 "type": "object",
7 "additionalProperties": false,
8 "required": [
9 "status",
10 "type",
11 "data"
12 ],
13 "properties": {
14 "status": {
15 "type": "integer",
16 "const": 200
17 },
18 "type": {
19 "type": "string",
20 "const": "topology"
21 },
22 "v": {
23 "type": "integer",
24 "minimum": 0,
25 "description": "Optional Function transport protocol version. This is part of the Function response envelope, not topology data."
26 },
27 "has_history": {
28 "type": "boolean",
29 "const": false
30 },
31 "accepted_params": {
32 "type": "array",
33 "items": {
34 "type": "string"
35 },
36 "uniqueItems": true
37 },
38 "required_params": {
39 "type": "array",
40 "items": {
41 "type": "object"
42 }
43 },
44 "help": {
45 "type": "string"
46 },
47 "update_every": {
48 "type": "integer",
49 "minimum": 0
50 },
51 "expires": {
52 "type": "integer",
53 "minimum": 0
54 },
55 "data": {
56 "$ref": "#/$defs/topology_data"
57 }
58 },
59 "$defs": {
60 "topology_data": {
61 "type": "object",
62 "additionalProperties": false,
63 "required": [
64 "schema_version",
65 "producer",
66 "collected_at",
67 "dictionaries",
68 "types",
69 "actors",
70 "links"
71 ],
72 "properties": {
73 "schema_version": {
74 "type": "string",
75 "const": "netdata.topology.v1"
76 },
77 "producer": {
78 "$ref": "#/$defs/producer"
79 },
80 "collected_at": {
81 "type": "string",
82 "format": "date-time"
83 },
84 "valid_after": {
85 "type": "string",
86 "format": "date-time"
87 },
88 "valid_until": {
89 "type": "string",
90 "format": "date-time"
91 },
92 "view": {
93 "$ref": "#/$defs/view"
94 },
95 "dictionaries": {
96 "$ref": "#/$defs/dictionaries"
97 },
98 "types": {
99 "$ref": "#/$defs/type_registry"
100 },
101 "presentation": {
102 "$ref": "#/$defs/topology_presentation"
103 },
104 "correlation": {
105 "$ref": "#/$defs/topology_correlation"
106 },
107 "actors": {
108 "$ref": "#/$defs/table"
109 },
110 "links": {
111 "$ref": "#/$defs/table"
112 },
113 "evidence": {
114 "type": "object",
115 "propertyNames": {
116 "$ref": "#/$defs/id"
117 },
118 "additionalProperties": {
119 "$ref": "#/$defs/evidence_section"
120 },
121 "default": {}
122 },
123 "tables": {
124 "$ref": "#/$defs/detail_tables"
125 },
126 "overlays": {
127 "$ref": "#/$defs/overlay_refs"
128 },
129 "stats": {
130 "type": "object",
131 "additionalProperties": {
132 "$ref": "#/$defs/scalar_or_array"
133 },
134 "default": {}
135 },
136 "extensions": {
137 "type": "object",
138 "description": "Producer-private metadata. Extensions must be small, non-sensitive, and must not be required for core aggregation.",
139 "additionalProperties": {
140 "$ref": "#/$defs/scalar_or_array"
141 },
142 "default": {}
143 }
144 }
145 },
146 "producer": {
147 "type": "object",
148 "additionalProperties": false,
149 "required": [
150 "source",
151 "instance"
152 ],
153 "properties": {
154 "source": {
155 "$ref": "#/$defs/id",
156 "description": "Stable producer id, for example network-connections, streaming, snmp-l2, vsphere."
157 },
158 "instance": {
159 "type": "string",
160 "description": "Source-local producer instance id."
161 },
162 "node_id": {
163 "type": "string"
164 },
165 "machine_guid": {
166 "type": "string"
167 },
168 "agent_version": {
169 "type": "string"
170 },
171 "plugin": {
172 "type": "string"
173 },
174 "capabilities": {
175 "type": "array",
176 "items": {
177 "$ref": "#/$defs/id"
178 },
179 "uniqueItems": true,
180 "default": []
181 }
182 }
183 },
184 "view": {
185 "type": "object",
186 "additionalProperties": false,
187 "properties": {
188 "id": {
189 "$ref": "#/$defs/id"
190 },
191 "scope": {
192 "$ref": "#/$defs/id"
193 },
194 "mode": {
195 "type": "string",
196 "enum": [
197 "aggregated",
198 "detailed"
199 ]
200 },
201 "supported_modes": {
202 "type": "array",
203 "description": "Modes this producer can return with different semantics. Omit or provide one value for mode-invariant topologies so UIs do not show a misleading mode selector.",
204 "items": {
205 "type": "string",
206 "enum": [
207 "aggregated",
208 "detailed"
209 ]
210 },
211 "uniqueItems": true,
212 "default": []
213 },
214 "group_by": {
215 "type": "array",
216 "items": {
217 "$ref": "#/$defs/id"
218 },
219 "uniqueItems": true,
220 "default": []
221 }
222 }
223 },
224 "dictionaries": {
225 "type": "object",
226 "additionalProperties": {
227 "type": "array",
228 "items": {
229 "$ref": "#/$defs/scalar_or_array"
230 }
231 },
232 "properties": {
233 "strings": {
234 "type": "array",
235 "items": {
236 "type": "string"
237 },
238 "default": []
239 }
240 }
241 },
242 "type_registry": {
243 "type": "object",
244 "additionalProperties": false,
245 "required": [
246 "actor_types",
247 "link_types"
248 ],
249 "properties": {
250 "actor_types": {
251 "$ref": "#/$defs/actor_type_map"
252 },
253 "link_types": {
254 "$ref": "#/$defs/link_type_map"
255 },
256 "port_types": {
257 "$ref": "#/$defs/port_type_map"
258 },
259 "evidence_types": {
260 "$ref": "#/$defs/evidence_type_map"
261 },
262 "table_types": {
263 "$ref": "#/$defs/table_type_map"
264 },
265 "overlay_templates": {
266 "$ref": "#/$defs/overlay_template_map"
267 },
268 "aggregation_scopes": {
269 "$ref": "#/$defs/aggregation_scope_map"
270 }
271 }
272 },
273 "actor_type_map": {
274 "type": "object",
275 "propertyNames": {
276 "$ref": "#/$defs/id"
277 },
278 "additionalProperties": {
279 "$ref": "#/$defs/actor_type"
280 }
281 },
282 "link_type_map": {
283 "type": "object",
284 "propertyNames": {
285 "$ref": "#/$defs/id"
286 },
287 "additionalProperties": {
288 "$ref": "#/$defs/link_type"
289 }
290 },
291 "port_type_map": {
292 "type": "object",
293 "propertyNames": {
294 "$ref": "#/$defs/id"
295 },
296 "additionalProperties": {
297 "$ref": "#/$defs/port_type"
298 },
299 "default": {}
300 },
301 "evidence_type_map": {
302 "type": "object",
303 "propertyNames": {
304 "$ref": "#/$defs/id"
305 },
306 "additionalProperties": {
307 "$ref": "#/$defs/evidence_type"
308 },
309 "default": {}
310 },
311 "table_type_map": {
312 "type": "object",
313 "propertyNames": {
314 "$ref": "#/$defs/id"
315 },
316 "additionalProperties": {
317 "$ref": "#/$defs/table_type"
318 },
319 "default": {}
320 },
321 "overlay_template_map": {
322 "type": "object",
323 "propertyNames": {
324 "$ref": "#/$defs/id"
325 },
326 "additionalProperties": {
327 "$ref": "#/$defs/overlay_template"
328 },
329 "default": {}
330 },
331 "aggregation_scope_map": {
332 "type": "object",
333 "propertyNames": {
334 "$ref": "#/$defs/id"
335 },
336 "additionalProperties": {
337 "$ref": "#/$defs/aggregation_scope"
338 },
339 "default": {}
340 },
341 "actor_type": {
342 "type": "object",
343 "additionalProperties": false,
344 "required": [
345 "layer",
346 "identity"
347 ],
348 "properties": {
349 "layer": {
350 "$ref": "#/$defs/layer"
351 },
352 "identity": {
353 "type": "array",
354 "description": "Actor-table column ids that form the source-local canonical identity.",
355 "items": {
356 "$ref": "#/$defs/id"
357 },
358 "minItems": 1,
359 "uniqueItems": true
360 },
361 "merge_identity": {
362 "type": "array",
363 "description": "Actor-table column ids that may be used by a cross-node or cross-source aggregator.",
364 "items": {
365 "$ref": "#/$defs/id"
366 },
367 "uniqueItems": true,
368 "default": []
369 },
370 "parent_identity": {
371 "type": "array",
372 "description": "Actor-table column ids that identify the actor this actor lives on or belongs to.",
373 "items": {
374 "$ref": "#/$defs/id"
375 },
376 "uniqueItems": true,
377 "default": []
378 },
379 "aggregation_scopes": {
380 "type": "array",
381 "items": {
382 "$ref": "#/$defs/id"
383 },
384 "uniqueItems": true,
385 "default": []
386 },
387 "search": {
388 "$ref": "#/$defs/actor_search_policy"
389 },
390 "presentation": {
391 "$ref": "#/$defs/actor_type_presentation"
392 }
393 }
394 },
395 "link_type": {
396 "type": "object",
397 "additionalProperties": false,
398 "required": [
399 "orientation",
400 "direction_role",
401 "aggregation"
402 ],
403 "properties": {
404 "orientation": {
405 "type": "string",
406 "enum": [
407 "directed",
408 "undirected",
409 "hierarchical",
410 "observed_bidirectional"
411 ]
412 },
413 "direction_role": {
414 "type": "string",
415 "enum": [
416 "none",
417 "flow",
418 "dependency",
419 "ownership",
420 "observation"
421 ]
422 },
423 "semantic_role": {
424 "$ref": "#/$defs/link_semantic_role"
425 },
426 "aggregation": {
427 "$ref": "#/$defs/link_aggregation"
428 },
429 "evidence_types": {
430 "type": "array",
431 "items": {
432 "$ref": "#/$defs/id"
433 },
434 "uniqueItems": true,
435 "default": []
436 },
437 "overlay_templates": {
438 "type": "array",
439 "items": {
440 "$ref": "#/$defs/id"
441 },
442 "uniqueItems": true,
443 "default": []
444 },
445 "presentation": {
446 "$ref": "#/$defs/link_type_presentation"
447 }
448 }
449 },
450 "port_type": {
451 "type": "object",
452 "additionalProperties": false,
453 "properties": {
454 "presentation": {
455 "$ref": "#/$defs/port_type_presentation"
456 }
457 }
458 },
459 "topology_presentation": {
460 "type": "object",
461 "description": "Graph-level presentation policy. Type-specific visual tokens live inside actor, link, and port type definitions; this object carries only cross-type policies such as selection, legend, port field labels, and scale-key labels.",
462 "additionalProperties": false,
463 "properties": {
464 "profile_version": {
465 "type": "string",
466 "description": "Producer presentation profile version for diagnostics. This does not replace data.schema_version."
467 },
468 "selection": {
469 "$ref": "#/$defs/selection_presentation"
470 },
471 "legend": {
472 "$ref": "#/$defs/presentation_legend"
473 },
474 "port_fields": {
475 "type": "array",
476 "items": {
477 "$ref": "#/$defs/presentation_field"
478 },
479 "default": []
480 },
481 "scale_keys": {
482 "type": "object",
483 "propertyNames": {
484 "$ref": "#/$defs/id"
485 },
486 "additionalProperties": {
487 "$ref": "#/$defs/scale_key_presentation"
488 },
489 "default": {}
490 }
491 }
492 },
493 "topology_correlation": {
494 "type": "object",
495 "description": "Producer-visible correlation contract used by aggregators to resolve loose relationship sides, replace weaker actors, merge/enrich equivalent actors, or resolve visible correlation actors across independently produced topology maps. This is not an aggregator state dump; final aggregated payloads remain normal topology graphs.",
496 "additionalProperties": false,
497 "required": [
498 "rules"
499 ],
500 "properties": {
501 "rules": {
502 "type": "object",
503 "description": "Correlation rules keyed by producer-local rule id. Rules define how keys are built, the action to apply on a match, and the link type used for the final visible graph.",
504 "propertyNames": {
505 "$ref": "#/$defs/id"
506 },
507 "additionalProperties": {
508 "$ref": "#/$defs/correlation_rule"
509 },
510 "minProperties": 1
511 },
512 "points": {
513 "description": "Compact table of visible correlation actors and their match keys when the input graph materializes correlation points. Required columns are actor, rule, and every column referenced by each referenced rule key.",
514 "$ref": "#/$defs/table"
515 },
516 "claims": {
517 "description": "Compact table of real actors and the keys they can satisfy. Required columns are actor, rule, and every column referenced by each referenced rule key.",
518 "$ref": "#/$defs/table"
519 }
520 }
521 },
522 "correlation_rule": {
523 "type": "object",
524 "additionalProperties": false,
525 "required": [
526 "action",
527 "priority",
528 "key_space",
529 "key",
530 "point_actor_types",
531 "output_link_type"
532 ],
533 "properties": {
534 "action": {
535 "type": "string",
536 "description": "Visible output semantics when a point matches a claim. absorb removes matching correlation actors and rewrites links. link keeps the correlation actor visible and links it to the matched actor.",
537 "enum": [
538 "absorb",
539 "link"
540 ]
541 },
542 "class": {
543 "type": "string",
544 "description": "Topology-agnostic correlation outcome class. Older payloads may omit this and rely on action only.",
545 "enum": [
546 "resolve_loose_side",
547 "replace_actor",
548 "merge_enrich_actor"
549 ]
550 },
551 "priority": {
552 "type": "integer",
553 "description": "Lower numbers run first. Exact rules should use higher priority than partial/broader rules.",
554 "minimum": 0
555 },
556 "key_space": {
557 "$ref": "#/$defs/id"
558 },
559 "key": {
560 "type": "array",
561 "description": "Declarative key template. The aggregator concatenates normalized column values and literals; it does not execute code or know the semantic meaning of the columns.",
562 "items": {
563 "$ref": "#/$defs/correlation_key_part"
564 },
565 "minItems": 1
566 },
567 "point_actor_types": {
568 "type": "array",
569 "description": "Actor type ids that represent visible correlation points for this rule. Rules that operate only on loose relationship-side facts may leave this empty in a future schema revision, but current payloads must provide at least one id when points are emitted.",
570 "items": {
571 "$ref": "#/$defs/id"
572 },
573 "minItems": 1,
574 "uniqueItems": true
575 },
576 "claim_actor_types": {
577 "type": "array",
578 "description": "Actor type ids that may satisfy points for this rule. Empty means any actor type that emits a claim row may satisfy the rule.",
579 "items": {
580 "$ref": "#/$defs/id"
581 },
582 "uniqueItems": true,
583 "default": []
584 },
585 "correlation_link_types": {
586 "type": "array",
587 "description": "Link type ids that connect real actors to correlation actors and may be consumed or rewritten by this rule.",
588 "items": {
589 "$ref": "#/$defs/id"
590 },
591 "uniqueItems": true,
592 "default": []
593 },
594 "output_link_type": {
595 "description": "Link type id to emit for rewritten absorb links or visible partial/link correlations.",
596 "$ref": "#/$defs/id"
597 }
598 }
599 },
600 "correlation_key_part": {
601 "oneOf": [
602 {
603 "type": "object",
604 "additionalProperties": false,
605 "required": [
606 "column"
607 ],
608 "properties": {
609 "column": {
610 "$ref": "#/$defs/id"
611 }
612 }
613 },
614 {
615 "type": "object",
616 "additionalProperties": false,
617 "required": [
618 "literal"
619 ],
620 "properties": {
621 "literal": {
622 "type": "string",
623 "minLength": 1,
624 "maxLength": 64
625 }
626 }
627 }
628 ]
629 },
630 "actor_type_presentation": {
631 "type": "object",
632 "additionalProperties": false,
633 "properties": {
634 "label": {
635 "type": "string",
636 "minLength": 1
637 },
638 "role": {
639 "type": "string",
640 "enum": [
641 "actor",
642 "endpoint",
643 "group"
644 ]
645 },
646 "icon": {
647 "$ref": "#/$defs/icon_token"
648 },
649 "color_slot": {
650 "$ref": "#/$defs/color_slot"
651 },
652 "opacity": {
653 "$ref": "#/$defs/opacity_token"
654 },
655 "border": {
656 "$ref": "#/$defs/border_presentation"
657 },
658 "annotation": {
659 "$ref": "#/$defs/annotation_presentation"
660 },
661 "size": {
662 "$ref": "#/$defs/actor_size_presentation"
663 },
664 "layout": {
665 "$ref": "#/$defs/actor_layout_presentation"
666 },
667 "label_policy": {
668 "$ref": "#/$defs/label_policy"
669 },
670 "ports": {
671 "$ref": "#/$defs/actor_ports_presentation"
672 },
673 "hover": {
674 "$ref": "#/$defs/hover_presentation"
675 },
676 "modal": {
677 "$ref": "#/$defs/modal_presentation"
678 }
679 }
680 },
681 "link_type_presentation": {
682 "type": "object",
683 "additionalProperties": false,
684 "properties": {
685 "label": {
686 "type": "string",
687 "minLength": 1
688 },
689 "color_slot": {
690 "$ref": "#/$defs/color_slot"
691 },
692 "opacity": {
693 "$ref": "#/$defs/opacity_token"
694 },
695 "line_style": {
696 "type": "string",
697 "enum": [
698 "solid",
699 "dashed",
700 "dotted"
701 ]
702 },
703 "width": {
704 "$ref": "#/$defs/width_token"
705 },
706 "curve": {
707 "type": "string",
708 "enum": [
709 "straight",
710 "clockwise",
711 "counter_clockwise",
712 "auto"
713 ]
714 },
715 "arrow": {
716 "type": "string",
717 "enum": [
718 "none",
719 "forward",
720 "reverse",
721 "both",
722 "auto"
723 ]
724 },
725 "variable": {
726 "$ref": "#/$defs/link_variable_presentation"
727 },
728 "hover": {
729 "$ref": "#/$defs/hover_presentation"
730 },
731 "layout": {
732 "$ref": "#/$defs/link_layout_presentation"
733 },
734 "modal": {
735 "$ref": "#/$defs/modal_presentation"
736 }
737 }
738 },
739 "link_layout_presentation": {
740 "type": "object",
741 "description": "Tokenized layout hints for the UI force graph. Producers choose relative tokens; the UI owns numeric force and distance values.",
742 "additionalProperties": false,
743 "properties": {
744 "strength": {
745 "$ref": "#/$defs/layout_strength_token"
746 },
747 "distance": {
748 "$ref": "#/$defs/layout_distance_token"
749 }
750 }
751 },
752 "actor_layout_presentation": {
753 "type": "object",
754 "description": "Tokenized actor layout hints for the UI force graph. Producers choose relative tokens; the UI owns numeric force values.",
755 "additionalProperties": false,
756 "properties": {
757 "repulsion": {
758 "$ref": "#/$defs/layout_strength_token"
759 }
760 }
761 },
762 "port_type_presentation": {
763 "type": "object",
764 "additionalProperties": false,
765 "properties": {
766 "label": {
767 "type": "string",
768 "minLength": 1
769 },
770 "color_slot": {
771 "$ref": "#/$defs/color_slot"
772 },
773 "opacity": {
774 "$ref": "#/$defs/opacity_token"
775 }
776 }
777 },
778 "selection_presentation": {
779 "type": "object",
780 "additionalProperties": false,
781 "properties": {
782 "actor_click": {
783 "$ref": "#/$defs/actor_click_presentation"
784 }
785 }
786 },
787 "actor_click_presentation": {
788 "type": "object",
789 "additionalProperties": false,
790 "required": [
791 "mode"
792 ],
793 "properties": {
794 "mode": {
795 "type": "string",
796 "enum": [
797 "none",
798 "highlight_connections",
799 "highlight_path"
800 ]
801 },
802 "path_table": {
803 "$ref": "#/$defs/id"
804 },
805 "path_owner_column": {
806 "$ref": "#/$defs/id"
807 },
808 "path_actor_column": {
809 "$ref": "#/$defs/id"
810 },
811 "path_order_column": {
812 "$ref": "#/$defs/id"
813 }
814 },
815 "allOf": [
816 {
817 "if": {
818 "properties": {
819 "mode": {
820 "const": "highlight_path"
821 }
822 },
823 "required": [
824 "mode"
825 ]
826 },
827 "then": {
828 "required": [
829 "path_table",
830 "path_actor_column",
831 "path_order_column"
832 ]
833 }
834 }
835 ]
836 },
837 "presentation_legend": {
838 "type": "object",
839 "additionalProperties": false,
840 "properties": {
841 "actors": {
842 "type": "array",
843 "items": {
844 "$ref": "#/$defs/legend_entry"
845 },
846 "default": []
847 },
848 "links": {
849 "type": "array",
850 "items": {
851 "$ref": "#/$defs/legend_entry"
852 },
853 "default": []
854 },
855 "ports": {
856 "type": "array",
857 "items": {
858 "$ref": "#/$defs/legend_entry"
859 },
860 "default": []
861 }
862 }
863 },
864 "legend_entry": {
865 "type": "object",
866 "additionalProperties": false,
867 "required": [
868 "type"
869 ],
870 "properties": {
871 "type": {
872 "$ref": "#/$defs/id"
873 },
874 "label": {
875 "type": "string",
876 "minLength": 1
877 }
878 }
879 },
880 "presentation_field": {
881 "type": "object",
882 "additionalProperties": false,
883 "required": [
884 "key",
885 "label"
886 ],
887 "properties": {
888 "key": {
889 "$ref": "#/$defs/id"
890 },
891 "label": {
892 "type": "string"
893 }
894 }
895 },
896 "scale_key_presentation": {
897 "type": "object",
898 "additionalProperties": false,
899 "required": [
900 "label"
901 ],
902 "properties": {
903 "label": {
904 "type": "string",
905 "minLength": 1
906 },
907 "unit": {
908 "type": "string"
909 }
910 }
911 },
912 "border_presentation": {
913 "type": "object",
914 "additionalProperties": false,
915 "properties": {
916 "enabled": {
917 "type": "boolean",
918 "default": true
919 },
920 "color_slot": {
921 "$ref": "#/$defs/color_slot"
922 },
923 "style": {
924 "type": "string",
925 "enum": [
926 "solid",
927 "dashed",
928 "dotted"
929 ],
930 "default": "solid"
931 }
932 }
933 },
934 "annotation_presentation": {
935 "type": "object",
936 "additionalProperties": false,
937 "properties": {
938 "color_slot": {
939 "$ref": "#/$defs/color_slot"
940 },
941 "style": {
942 "type": "string",
943 "enum": [
944 "ring",
945 "dot",
946 "none"
947 ]
948 }
949 }
950 },
951 "actor_size_presentation": {
952 "type": "object",
953 "additionalProperties": false,
954 "required": [
955 "mode"
956 ],
957 "properties": {
958 "mode": {
959 "type": "string",
960 "enum": [
961 "fixed",
962 "link_count",
963 "metric"
964 ]
965 },
966 "metric_column": {
967 "$ref": "#/$defs/id"
968 },
969 "scale": {
970 "$ref": "#/$defs/actor_size_scale_token"
971 }
972 },
973 "allOf": [
974 {
975 "if": {
976 "properties": {
977 "mode": {
978 "const": "metric"
979 }
980 },
981 "required": [
982 "mode"
983 ]
984 },
985 "then": {
986 "required": [
987 "metric_column"
988 ]
989 }
990 }
991 ]
992 },
993 "actor_search_policy": {
994 "type": "object",
995 "description": "Producer-declared searchable fields for this actor type. This replaces UI hardcoded traversal of domain-specific actor attributes.",
996 "additionalProperties": false,
997 "properties": {
998 "enabled": {
999 "type": "boolean",
1000 "default": true
1001 },
1002 "columns": {
1003 "type": "array",
1004 "description": "Actor-table column ids whose scalar values should be indexed for graph search.",
1005 "items": {
1006 "$ref": "#/$defs/id"
1007 },
1008 "uniqueItems": true,
1009 "default": []
1010 },
1011 "label_keys": {
1012 "type": "array",
1013 "description": "actor_labels.key values whose label values should be indexed for graph search.",
1014 "items": {
1015 "$ref": "#/$defs/id"
1016 },
1017 "uniqueItems": true,
1018 "default": []
1019 }
1020 }
1021 },
1022 "label_policy": {
1023 "type": "object",
1024 "additionalProperties": false,
1025 "properties": {
1026 "columns": {
1027 "type": "array",
1028 "description": "Actor-table columns that are safe to use as display labels, in priority order.",
1029 "items": {
1030 "$ref": "#/$defs/id"
1031 },
1032 "uniqueItems": true,
1033 "default": []
1034 },
1035 "fallback": {
1036 "type": "string",
1037 "enum": [
1038 "type_label",
1039 "row_index",
1040 "none"
1041 ],
1042 "default": "type_label"
1043 },
1044 "max_length": {
1045 "type": "integer",
1046 "minimum": 8,
1047 "maximum": 256,
1048 "default": 80
1049 },
1050 "array": {
1051 "type": "string",
1052 "enum": [
1053 "reject",
1054 "first",
1055 "summarize"
1056 ],
1057 "default": "reject"
1058 }
1059 }
1060 },
1061 "actor_ports_presentation": {
1062 "type": "object",
1063 "additionalProperties": false,
1064 "properties": {
1065 "show_bullets": {
1066 "type": "boolean",
1067 "default": false
1068 },
1069 "sources": {
1070 "type": "array",
1071 "description": "Port-bullet sources. The UI derives bullets from these compact table references instead of using domain-specific hardcoding.",
1072 "items": {
1073 "$ref": "#/$defs/port_source_presentation"
1074 },
1075 "default": []
1076 }
1077 }
1078 },
1079 "port_source_presentation": {
1080 "type": "object",
1081 "additionalProperties": false,
1082 "required": [
1083 "source",
1084 "actor_column",
1085 "name_column"
1086 ],
1087 "properties": {
1088 "source": {
1089 "type": "string",
1090 "enum": [
1091 "links",
1092 "evidence",
1093 "actor_table"
1094 ]
1095 },
1096 "table": {
1097 "$ref": "#/$defs/id",
1098 "description": "Actor detail table id when source is actor_table."
1099 },
1100 "evidence": {
1101 "$ref": "#/$defs/id",
1102 "description": "Evidence section or evidence type id when source is evidence."
1103 },
1104 "actor_column": {
1105 "$ref": "#/$defs/id",
1106 "description": "Column in the source table that references the actor receiving the bullet."
1107 },
1108 "name_column": {
1109 "$ref": "#/$defs/id",
1110 "description": "Column in the source table used as the bullet key or label."
1111 },
1112 "value_column": {
1113 "$ref": "#/$defs/id",
1114 "description": "Optional numeric source-table column whose values are summed for weighted bullet count and actor sizing."
1115 },
1116 "type_column": {
1117 "$ref": "#/$defs/id",
1118 "description": "Optional source-table column whose value selects a port_types entry."
1119 },
1120 "default_type": {
1121 "$ref": "#/$defs/id",
1122 "description": "Port type to use when type_column is absent or a row has no usable type value."
1123 },
1124 "status_column": {
1125 "$ref": "#/$defs/id"
1126 },
1127 "mode_column": {
1128 "$ref": "#/$defs/id"
1129 },
1130 "role_column": {
1131 "$ref": "#/$defs/id"
1132 },
1133 "sources_column": {
1134 "$ref": "#/$defs/id"
1135 }
1136 }
1137 },
1138 "hover_presentation": {
1139 "type": "object",
1140 "additionalProperties": false,
1141 "properties": {
1142 "fields": {
1143 "type": "array",
1144 "items": {
1145 "$ref": "#/$defs/presentation_field"
1146 },
1147 "default": []
1148 }
1149 }
1150 },
1151 "modal_presentation": {
1152 "type": "object",
1153 "description": "Actor/link modal composition. Modal sections are recipes over existing topology tables; they must not duplicate high-cardinality facts only for UI display.",
1154 "additionalProperties": false,
1155 "properties": {
1156 "enabled": {
1157 "type": "boolean",
1158 "default": true
1159 },
1160 "labels": {
1161 "$ref": "#/$defs/modal_labels_presentation"
1162 },
1163 "mini_topology": {
1164 "$ref": "#/$defs/modal_mini_topology_presentation"
1165 },
1166 "sections": {
1167 "type": "array",
1168 "items": {
1169 "$ref": "#/$defs/modal_section"
1170 },
1171 "default": []
1172 }
1173 }
1174 },
1175 "modal_labels_presentation": {
1176 "type": "object",
1177 "description": "How to render actor labels in the actor modal. The default source is an actor-owned actor_labels table with one row per label value.",
1178 "additionalProperties": false,
1179 "properties": {
1180 "enabled": {
1181 "type": "boolean",
1182 "default": true
1183 },
1184 "table": {
1185 "$ref": "#/$defs/id",
1186 "default": "actor_labels"
1187 },
1188 "actor_column": {
1189 "$ref": "#/$defs/id",
1190 "default": "actor"
1191 },
1192 "key_column": {
1193 "$ref": "#/$defs/id",
1194 "default": "key"
1195 },
1196 "value_column": {
1197 "$ref": "#/$defs/id",
1198 "default": "value"
1199 },
1200 "source_column": {
1201 "$ref": "#/$defs/id",
1202 "default": "source"
1203 },
1204 "kind_column": {
1205 "$ref": "#/$defs/id",
1206 "default": "kind"
1207 },
1208 "value_index_column": {
1209 "$ref": "#/$defs/id",
1210 "default": "value_index"
1211 },
1212 "identification": {
1213 "$ref": "#/$defs/modal_label_identification_presentation"
1214 }
1215 }
1216 },
1217 "modal_label_identification_presentation": {
1218 "type": "object",
1219 "description": "Producer-selected actor label keys that the UI should render in the actor modal identification/header area. The full label table remains available separately.",
1220 "additionalProperties": false,
1221 "properties": {
1222 "enabled": {
1223 "type": "boolean",
1224 "default": true
1225 },
1226 "fields": {
1227 "type": "array",
1228 "items": {
1229 "$ref": "#/$defs/modal_label_identification_field"
1230 },
1231 "default": []
1232 }
1233 }
1234 },
1235 "modal_label_identification_field": {
1236 "type": "object",
1237 "additionalProperties": false,
1238 "required": [
1239 "key",
1240 "label"
1241 ],
1242 "properties": {
1243 "key": {
1244 "type": "string",
1245 "minLength": 1,
1246 "maxLength": 128
1247 },
1248 "label": {
1249 "type": "string",
1250 "minLength": 1,
1251 "maxLength": 128
1252 },
1253 "max_values": {
1254 "type": "integer",
1255 "minimum": 1,
1256 "default": 1
1257 }
1258 }
1259 },
1260 "modal_mini_topology_presentation": {
1261 "type": "object",
1262 "description": "Depth-1 modal topology preview built from existing actors and graph links.",
1263 "additionalProperties": false,
1264 "properties": {
1265 "enabled": {
1266 "type": "boolean",
1267 "default": true
1268 },
1269 "depth": {
1270 "type": "integer",
1271 "const": 1,
1272 "default": 1
1273 },
1274 "include_link_types": {
1275 "type": "array",
1276 "items": {
1277 "$ref": "#/$defs/id"
1278 },
1279 "uniqueItems": true,
1280 "default": []
1281 },
1282 "exclude_link_types": {
1283 "type": "array",
1284 "items": {
1285 "$ref": "#/$defs/id"
1286 },
1287 "uniqueItems": true,
1288 "default": []
1289 }
1290 }
1291 },
1292 "modal_section": {
1293 "type": "object",
1294 "additionalProperties": false,
1295 "required": [
1296 "id",
1297 "label",
1298 "source",
1299 "columns"
1300 ],
1301 "properties": {
1302 "id": {
1303 "$ref": "#/$defs/id"
1304 },
1305 "label": {
1306 "type": "string",
1307 "minLength": 1
1308 },
1309 "order": {
1310 "type": "integer",
1311 "default": 0
1312 },
1313 "source": {
1314 "$ref": "#/$defs/modal_source"
1315 },
1316 "owner_filter": {
1317 "$ref": "#/$defs/modal_owner_filter"
1318 },
1319 "row_filters": {
1320 "type": "array",
1321 "items": {
1322 "$ref": "#/$defs/modal_row_filter"
1323 },
1324 "default": []
1325 },
1326 "columns": {
1327 "type": "array",
1328 "items": {
1329 "$ref": "#/$defs/modal_column"
1330 },
1331 "minItems": 1
1332 },
1333 "sort": {
1334 "$ref": "#/$defs/modal_sort"
1335 },
1336 "empty_label": {
1337 "type": "string"
1338 }
1339 }
1340 },
1341 "modal_source": {
1342 "type": "object",
1343 "additionalProperties": false,
1344 "required": [
1345 "kind"
1346 ],
1347 "properties": {
1348 "kind": {
1349 "type": "string",
1350 "enum": [
1351 "actors",
1352 "links",
1353 "evidence",
1354 "actor_table",
1355 "relationship_table"
1356 ]
1357 },
1358 "table": {
1359 "$ref": "#/$defs/id",
1360 "description": "Detail table id when kind is actor_table or relationship_table."
1361 },
1362 "evidence": {
1363 "$ref": "#/$defs/id",
1364 "description": "Evidence section id when kind is evidence."
1365 }
1366 },
1367 "allOf": [
1368 {
1369 "if": {
1370 "required": [
1371 "kind"
1372 ],
1373 "properties": {
1374 "kind": {
1375 "const": "evidence"
1376 }
1377 }
1378 },
1379 "then": {
1380 "required": [
1381 "evidence"
1382 ]
1383 }
1384 },
1385 {
1386 "if": {
1387 "required": [
1388 "kind"
1389 ],
1390 "properties": {
1391 "kind": {
1392 "enum": [
1393 "actor_table",
1394 "relationship_table"
1395 ]
1396 }
1397 }
1398 },
1399 "then": {
1400 "required": [
1401 "table"
1402 ]
1403 }
1404 }
1405 ]
1406 },
1407 "modal_owner_filter": {
1408 "type": "object",
1409 "additionalProperties": false,
1410 "required": [
1411 "mode"
1412 ],
1413 "properties": {
1414 "mode": {
1415 "type": "string",
1416 "enum": [
1417 "none",
1418 "actor_column",
1419 "link_column",
1420 "incident_link",
1421 "incident_evidence",
1422 "selected_link"
1423 ]
1424 },
1425 "actor_column": {
1426 "$ref": "#/$defs/id"
1427 },
1428 "link_column": {
1429 "$ref": "#/$defs/id"
1430 },
1431 "src_actor_column": {
1432 "$ref": "#/$defs/id"
1433 },
1434 "dst_actor_column": {
1435 "$ref": "#/$defs/id"
1436 }
1437 },
1438 "allOf": [
1439 {
1440 "if": {
1441 "required": [
1442 "mode"
1443 ],
1444 "properties": {
1445 "mode": {
1446 "const": "actor_column"
1447 }
1448 }
1449 },
1450 "then": {
1451 "required": [
1452 "actor_column"
1453 ]
1454 }
1455 },
1456 {
1457 "if": {
1458 "required": [
1459 "mode"
1460 ],
1461 "properties": {
1462 "mode": {
1463 "enum": [
1464 "link_column",
1465 "selected_link"
1466 ]
1467 }
1468 }
1469 },
1470 "then": {
1471 "required": [
1472 "link_column"
1473 ]
1474 }
1475 },
1476 {
1477 "if": {
1478 "required": [
1479 "mode"
1480 ],
1481 "properties": {
1482 "mode": {
1483 "enum": [
1484 "incident_link",
1485 "incident_evidence"
1486 ]
1487 }
1488 }
1489 },
1490 "then": {
1491 "required": [
1492 "src_actor_column",
1493 "dst_actor_column"
1494 ]
1495 }
1496 }
1497 ]
1498 },
1499 "modal_row_filter": {
1500 "type": "object",
1501 "additionalProperties": false,
1502 "required": [
1503 "column",
1504 "op"
1505 ],
1506 "properties": {
1507 "column": {
1508 "$ref": "#/$defs/id"
1509 },
1510 "op": {
1511 "type": "string",
1512 "enum": [
1513 "eq",
1514 "ne",
1515 "in",
1516 "not_in",
1517 "exists",
1518 "missing"
1519 ]
1520 },
1521 "value": {
1522 "$ref": "#/$defs/cell_value"
1523 },
1524 "values": {
1525 "type": "array",
1526 "items": {
1527 "$ref": "#/$defs/cell_value"
1528 }
1529 }
1530 },
1531 "allOf": [
1532 {
1533 "if": {
1534 "required": [
1535 "op"
1536 ],
1537 "properties": {
1538 "op": {
1539 "enum": [
1540 "eq",
1541 "ne"
1542 ]
1543 }
1544 }
1545 },
1546 "then": {
1547 "required": [
1548 "value"
1549 ]
1550 }
1551 },
1552 {
1553 "if": {
1554 "required": [
1555 "op"
1556 ],
1557 "properties": {
1558 "op": {
1559 "enum": [
1560 "in",
1561 "not_in"
1562 ]
1563 }
1564 }
1565 },
1566 "then": {
1567 "required": [
1568 "values"
1569 ],
1570 "properties": {
1571 "values": {
1572 "minItems": 1
1573 }
1574 }
1575 }
1576 }
1577 ]
1578 },
1579 "modal_column": {
1580 "type": "object",
1581 "additionalProperties": false,
1582 "required": [
1583 "id",
1584 "label",
1585 "projection"
1586 ],
1587 "properties": {
1588 "id": {
1589 "$ref": "#/$defs/id"
1590 },
1591 "label": {
1592 "type": "string",
1593 "minLength": 1
1594 },
1595 "projection": {
1596 "$ref": "#/$defs/modal_projection"
1597 },
1598 "cell": {
1599 "$ref": "#/$defs/modal_cell_type"
1600 },
1601 "visibility": {
1602 "$ref": "#/$defs/modal_visibility"
1603 },
1604 "align": {
1605 "type": "string",
1606 "enum": [
1607 "left",
1608 "center",
1609 "right"
1610 ],
1611 "default": "left"
1612 },
1613 "sortable": {
1614 "type": "boolean",
1615 "default": true
1616 },
1617 "badge_map": {
1618 "type": "object",
1619 "additionalProperties": {
1620 "$ref": "#/$defs/modal_badge_presentation"
1621 },
1622 "default": {}
1623 }
1624 }
1625 },
1626 "modal_projection": {
1627 "type": "object",
1628 "additionalProperties": false,
1629 "required": [
1630 "kind"
1631 ],
1632 "properties": {
1633 "kind": {
1634 "type": "string",
1635 "enum": [
1636 "direct",
1637 "actor_ref_label",
1638 "opposite_actor",
1639 "formatted_endpoint",
1640 "label_lookup",
1641 "json_path",
1642 "const",
1643 "coalesce",
1644 "selected_side_endpoint"
1645 ]
1646 },
1647 "column": {
1648 "$ref": "#/$defs/id"
1649 },
1650 "columns": {
1651 "type": "array",
1652 "items": {
1653 "$ref": "#/$defs/id"
1654 },
1655 "default": []
1656 },
1657 "value": {
1658 "$ref": "#/$defs/cell_value"
1659 },
1660 "actor_column": {
1661 "$ref": "#/$defs/id"
1662 },
1663 "src_actor_column": {
1664 "$ref": "#/$defs/id"
1665 },
1666 "dst_actor_column": {
1667 "$ref": "#/$defs/id"
1668 },
1669 "ip_column": {
1670 "$ref": "#/$defs/id"
1671 },
1672 "port_column": {
1673 "$ref": "#/$defs/id"
1674 },
1675 "protocol_column": {
1676 "$ref": "#/$defs/id"
1677 },
1678 "local_ip_column": {
1679 "$ref": "#/$defs/id"
1680 },
1681 "local_port_column": {
1682 "$ref": "#/$defs/id"
1683 },
1684 "remote_ip_column": {
1685 "$ref": "#/$defs/id"
1686 },
1687 "remote_port_column": {
1688 "$ref": "#/$defs/id"
1689 },
1690 "label_key": {
1691 "type": "string",
1692 "minLength": 1
1693 },
1694 "path": {
1695 "type": "string",
1696 "minLength": 1,
1697 "description": "JSON path for explicit scalar extraction from a json column. Use only for curated compatibility with producer-owned nested facts."
1698 },
1699 "fallback": {
1700 "$ref": "#/$defs/cell_value"
1701 }
1702 },
1703 "allOf": [
1704 {
1705 "if": {
1706 "required": [
1707 "kind"
1708 ],
1709 "properties": {
1710 "kind": {
1711 "const": "direct"
1712 }
1713 }
1714 },
1715 "then": {
1716 "required": [
1717 "column"
1718 ]
1719 }
1720 },
1721 {
1722 "if": {
1723 "required": [
1724 "kind"
1725 ],
1726 "properties": {
1727 "kind": {
1728 "const": "actor_ref_label"
1729 }
1730 }
1731 },
1732 "then": {
1733 "required": [
1734 "actor_column"
1735 ]
1736 }
1737 },
1738 {
1739 "if": {
1740 "required": [
1741 "kind"
1742 ],
1743 "properties": {
1744 "kind": {
1745 "const": "opposite_actor"
1746 }
1747 }
1748 },
1749 "then": {
1750 "required": [
1751 "src_actor_column",
1752 "dst_actor_column"
1753 ]
1754 }
1755 },
1756 {
1757 "if": {
1758 "required": [
1759 "kind"
1760 ],
1761 "properties": {
1762 "kind": {
1763 "const": "const"
1764 }
1765 }
1766 },
1767 "then": {
1768 "required": [
1769 "value"
1770 ]
1771 }
1772 },
1773 {
1774 "if": {
1775 "required": [
1776 "kind"
1777 ],
1778 "properties": {
1779 "kind": {
1780 "const": "formatted_endpoint"
1781 }
1782 }
1783 },
1784 "then": {
1785 "anyOf": [
1786 {
1787 "required": [
1788 "ip_column"
1789 ]
1790 },
1791 {
1792 "required": [
1793 "port_column"
1794 ]
1795 }
1796 ]
1797 }
1798 },
1799 {
1800 "if": {
1801 "required": [
1802 "kind"
1803 ],
1804 "properties": {
1805 "kind": {
1806 "const": "label_lookup"
1807 }
1808 }
1809 },
1810 "then": {
1811 "required": [
1812 "label_key"
1813 ]
1814 }
1815 },
1816 {
1817 "if": {
1818 "required": [
1819 "kind"
1820 ],
1821 "properties": {
1822 "kind": {
1823 "const": "json_path"
1824 }
1825 }
1826 },
1827 "then": {
1828 "required": [
1829 "column",
1830 "path"
1831 ]
1832 }
1833 },
1834 {
1835 "if": {
1836 "required": [
1837 "kind"
1838 ],
1839 "properties": {
1840 "kind": {
1841 "const": "coalesce"
1842 }
1843 }
1844 },
1845 "then": {
1846 "required": [
1847 "columns"
1848 ],
1849 "properties": {
1850 "columns": {
1851 "minItems": 1
1852 }
1853 }
1854 }
1855 },
1856 {
1857 "if": {
1858 "required": [
1859 "kind"
1860 ],
1861 "properties": {
1862 "kind": {
1863 "const": "selected_side_endpoint"
1864 }
1865 }
1866 },
1867 "then": {
1868 "allOf": [
1869 {
1870 "required": [
1871 "src_actor_column",
1872 "dst_actor_column"
1873 ]
1874 },
1875 {
1876 "anyOf": [
1877 {
1878 "required": [
1879 "local_ip_column"
1880 ]
1881 },
1882 {
1883 "required": [
1884 "local_port_column"
1885 ]
1886 }
1887 ]
1888 },
1889 {
1890 "anyOf": [
1891 {
1892 "required": [
1893 "remote_ip_column"
1894 ]
1895 },
1896 {
1897 "required": [
1898 "remote_port_column"
1899 ]
1900 }
1901 ]
1902 }
1903 ]
1904 }
1905 }
1906 ]
1907 },
1908 "modal_cell_type": {
1909 "type": "string",
1910 "enum": [
1911 "text",
1912 "number",
1913 "badge",
1914 "actor_link",
1915 "timestamp",
1916 "duration",
1917 "endpoint",
1918 "array_count",
1919 "debug_json"
1920 ]
1921 },
1922 "modal_visibility": {
1923 "type": "string",
1924 "enum": [
1925 "table",
1926 "expanded",
1927 "hidden",
1928 "debug"
1929 ],
1930 "default": "table"
1931 },
1932 "modal_badge_presentation": {
1933 "type": "object",
1934 "additionalProperties": false,
1935 "properties": {
1936 "label": {
1937 "type": "string"
1938 },
1939 "color_slot": {
1940 "$ref": "#/$defs/color_slot"
1941 },
1942 "opacity": {
1943 "$ref": "#/$defs/opacity_token"
1944 }
1945 }
1946 },
1947 "modal_sort": {
1948 "type": "object",
1949 "additionalProperties": false,
1950 "required": [
1951 "column"
1952 ],
1953 "properties": {
1954 "column": {
1955 "$ref": "#/$defs/id"
1956 },
1957 "direction": {
1958 "type": "string",
1959 "enum": [
1960 "asc",
1961 "desc"
1962 ],
1963 "default": "asc"
1964 }
1965 }
1966 },
1967 "link_variable_presentation": {
1968 "type": "object",
1969 "additionalProperties": false,
1970 "required": [
1971 "channel",
1972 "scale_key",
1973 "value_column"
1974 ],
1975 "properties": {
1976 "channel": {
1977 "type": "string",
1978 "enum": [
1979 "width",
1980 "opacity"
1981 ]
1982 },
1983 "scale_key": {
1984 "$ref": "#/$defs/id"
1985 },
1986 "value_column": {
1987 "$ref": "#/$defs/id"
1988 },
1989 "min": {
1990 "type": "string",
1991 "description": "Visual token lower bound for the selected channel."
1992 },
1993 "max": {
1994 "type": "string",
1995 "description": "Visual token upper bound for the selected channel."
1996 }
1997 },
1998 "allOf": [
1999 {
2000 "if": {
2001 "properties": {
2002 "channel": {
2003 "const": "width"
2004 }
2005 },
2006 "required": [
2007 "channel"
2008 ]
2009 },
2010 "then": {
2011 "properties": {
2012 "min": {
2013 "$ref": "#/$defs/width_token"
2014 },
2015 "max": {
2016 "$ref": "#/$defs/width_token"
2017 }
2018 }
2019 }
2020 },
2021 {
2022 "if": {
2023 "properties": {
2024 "channel": {
2025 "const": "opacity"
2026 }
2027 },
2028 "required": [
2029 "channel"
2030 ]
2031 },
2032 "then": {
2033 "properties": {
2034 "min": {
2035 "$ref": "#/$defs/opacity_token"
2036 },
2037 "max": {
2038 "$ref": "#/$defs/opacity_token"
2039 }
2040 }
2041 }
2042 }
2043 ]
2044 },
2045 "link_aggregation": {
2046 "type": "object",
2047 "additionalProperties": false,
2048 "required": [
2049 "direction"
2050 ],
2051 "properties": {
2052 "direction": {
2053 "type": "string",
2054 "enum": [
2055 "preserve",
2056 "ignore",
2057 "canonicalize_unordered"
2058 ]
2059 },
2060 "evidence": {
2061 "type": "string",
2062 "enum": [
2063 "append",
2064 "count",
2065 "drop"
2066 ],
2067 "default": "append"
2068 },
2069 "metrics": {
2070 "type": "object",
2071 "additionalProperties": {
2072 "$ref": "#/$defs/aggregation_rule"
2073 },
2074 "default": {}
2075 }
2076 }
2077 },
2078 "evidence_type": {
2079 "type": "object",
2080 "additionalProperties": false,
2081 "required": [
2082 "link_type",
2083 "role",
2084 "columns"
2085 ],
2086 "properties": {
2087 "link_type": {
2088 "$ref": "#/$defs/id"
2089 },
2090 "role": {
2091 "type": "string",
2092 "enum": [
2093 "relationship_evidence",
2094 "observation_evidence",
2095 "metric_sample"
2096 ]
2097 },
2098 "columns": {
2099 "type": "array",
2100 "items": {
2101 "$ref": "#/$defs/column"
2102 },
2103 "minItems": 1
2104 },
2105 "match_columns": {
2106 "type": "array",
2107 "description": "Evidence column ids required to preserve exact relationship matching.",
2108 "items": {
2109 "$ref": "#/$defs/id"
2110 },
2111 "uniqueItems": true,
2112 "default": []
2113 }
2114 }
2115 },
2116 "table_type": {
2117 "type": "object",
2118 "additionalProperties": false,
2119 "required": [
2120 "role",
2121 "owner",
2122 "aggregation",
2123 "columns"
2124 ],
2125 "properties": {
2126 "role": {
2127 "type": "string",
2128 "enum": [
2129 "actor_detail",
2130 "actor_inventory",
2131 "relationship_evidence",
2132 "relationship_summary"
2133 ]
2134 },
2135 "owner": {
2136 "type": "string",
2137 "enum": [
2138 "actor",
2139 "link",
2140 "evidence",
2141 "topology"
2142 ]
2143 },
2144 "aggregation": {
2145 "type": "string",
2146 "enum": [
2147 "none",
2148 "append",
2149 "deduplicate",
2150 "set",
2151 "set_union",
2152 "merge_metrics",
2153 "preserve",
2154 "sum",
2155 "min",
2156 "max",
2157 "last",
2158 "first",
2159 "latest"
2160 ]
2161 },
2162 "source_evidence": {
2163 "$ref": "#/$defs/id"
2164 },
2165 "columns": {
2166 "type": "array",
2167 "items": {
2168 "$ref": "#/$defs/column"
2169 },
2170 "minItems": 1
2171 },
2172 "presentation": {
2173 "$ref": "#/$defs/table_type_presentation"
2174 }
2175 }
2176 },
2177 "table_type_presentation": {
2178 "type": "object",
2179 "description": "Default table display metadata. Full modal sections live on actor/link type presentation and select from these table rows.",
2180 "additionalProperties": false,
2181 "properties": {
2182 "label": {
2183 "type": "string",
2184 "minLength": 1
2185 },
2186 "order": {
2187 "type": "integer",
2188 "default": 0
2189 },
2190 "default_visibility": {
2191 "$ref": "#/$defs/modal_visibility"
2192 },
2193 "columns": {
2194 "type": "array",
2195 "items": {
2196 "$ref": "#/$defs/modal_column"
2197 },
2198 "default": []
2199 }
2200 }
2201 },
2202 "overlay_template": {
2203 "type": "object",
2204 "additionalProperties": false,
2205 "required": [
2206 "provider",
2207 "merge"
2208 ],
2209 "properties": {
2210 "provider": {
2211 "type": "string",
2212 "enum": [
2213 "netdata.metrics",
2214 "netdata.function",
2215 "external"
2216 ]
2217 },
2218 "contexts": {
2219 "type": "array",
2220 "items": {
2221 "type": "string"
2222 },
2223 "uniqueItems": true,
2224 "default": []
2225 },
2226 "dimensions": {
2227 "type": "array",
2228 "items": {
2229 "type": "string"
2230 },
2231 "uniqueItems": true,
2232 "default": []
2233 },
2234 "selector_params": {
2235 "type": "array",
2236 "description": "Parameter names supplied by overlay refs.",
2237 "items": {
2238 "$ref": "#/$defs/id"
2239 },
2240 "uniqueItems": true,
2241 "default": []
2242 },
2243 "merge": {
2244 "$ref": "#/$defs/overlay_merge"
2245 }
2246 }
2247 },
2248 "overlay_merge": {
2249 "type": "object",
2250 "additionalProperties": false,
2251 "required": [
2252 "refs",
2253 "values"
2254 ],
2255 "properties": {
2256 "refs": {
2257 "type": "string",
2258 "enum": [
2259 "append",
2260 "set"
2261 ]
2262 },
2263 "values": {
2264 "type": "string",
2265 "enum": [
2266 "sum",
2267 "min",
2268 "max",
2269 "avg",
2270 "last",
2271 "none"
2272 ]
2273 }
2274 }
2275 },
2276 "aggregation_scope": {
2277 "type": "object",
2278 "additionalProperties": false,
2279 "required": [
2280 "columns"
2281 ],
2282 "properties": {
2283 "columns": {
2284 "type": "array",
2285 "items": {
2286 "$ref": "#/$defs/id"
2287 },
2288 "minItems": 1,
2289 "uniqueItems": true
2290 },
2291 "evidence_policy": {
2292 "type": "string",
2293 "enum": [
2294 "preserve",
2295 "count"
2296 ],
2297 "default": "preserve"
2298 }
2299 }
2300 },
2301 "evidence_section": {
2302 "type": "object",
2303 "additionalProperties": false,
2304 "required": [
2305 "type",
2306 "table"
2307 ],
2308 "properties": {
2309 "type": {
2310 "$ref": "#/$defs/id"
2311 },
2312 "table": {
2313 "$ref": "#/$defs/table"
2314 }
2315 }
2316 },
2317 "detail_tables": {
2318 "type": "object",
2319 "additionalProperties": false,
2320 "properties": {
2321 "actor": {
2322 "type": "object",
2323 "propertyNames": {
2324 "$ref": "#/$defs/id"
2325 },
2326 "additionalProperties": {
2327 "$ref": "#/$defs/detail_table"
2328 },
2329 "default": {}
2330 },
2331 "relationship": {
2332 "type": "object",
2333 "propertyNames": {
2334 "$ref": "#/$defs/id"
2335 },
2336 "additionalProperties": {
2337 "$ref": "#/$defs/detail_table"
2338 },
2339 "default": {}
2340 }
2341 },
2342 "default": {}
2343 },
2344 "detail_table": {
2345 "type": "object",
2346 "additionalProperties": false,
2347 "required": [
2348 "type",
2349 "table"
2350 ],
2351 "properties": {
2352 "type": {
2353 "$ref": "#/$defs/id"
2354 },
2355 "table": {
2356 "$ref": "#/$defs/table"
2357 }
2358 }
2359 },
2360 "overlay_refs": {
2361 "type": "object",
2362 "additionalProperties": false,
2363 "properties": {
2364 "refs": {
2365 "$ref": "#/$defs/table"
2366 }
2367 },
2368 "default": {}
2369 },
2370 "table": {
2371 "type": "object",
2372 "additionalProperties": false,
2373 "required": [
2374 "rows",
2375 "columns",
2376 "values"
2377 ],
2378 "properties": {
2379 "rows": {
2380 "type": "integer",
2381 "minimum": 0
2382 },
2383 "columns": {
2384 "type": "array",
2385 "items": {
2386 "$ref": "#/$defs/column"
2387 }
2388 },
2389 "values": {
2390 "type": "array",
2391 "items": {
2392 "$ref": "#/$defs/column_encoding"
2393 }
2394 }
2395 }
2396 },
2397 "column": {
2398 "type": "object",
2399 "additionalProperties": false,
2400 "required": [
2401 "id",
2402 "type"
2403 ],
2404 "properties": {
2405 "id": {
2406 "$ref": "#/$defs/id"
2407 },
2408 "type": {
2409 "type": "string",
2410 "enum": [
2411 "bool",
2412 "int",
2413 "uint",
2414 "float",
2415 "string",
2416 "string_ref",
2417 "timestamp",
2418 "duration",
2419 "ip",
2420 "ip_ref",
2421 "mac",
2422 "mac_ref",
2423 "actor_ref",
2424 "link_ref",
2425 "evidence_ref",
2426 "array",
2427 "json"
2428 ]
2429 },
2430 "dictionary": {
2431 "$ref": "#/$defs/id"
2432 },
2433 "nullable": {
2434 "type": "boolean",
2435 "default": false
2436 },
2437 "unit": {
2438 "type": "string"
2439 },
2440 "role": {
2441 "type": "string",
2442 "enum": [
2443 "identity",
2444 "merge_identity",
2445 "parent_identity",
2446 "group_key",
2447 "metric",
2448 "attribute",
2449 "timestamp",
2450 "reference"
2451 ]
2452 },
2453 "aggregation": {
2454 "$ref": "#/$defs/aggregation_rule"
2455 }
2456 }
2457 },
2458 "column_encoding": {
2459 "oneOf": [
2460 {
2461 "type": "object",
2462 "additionalProperties": false,
2463 "required": [
2464 "codec",
2465 "value"
2466 ],
2467 "properties": {
2468 "codec": {
2469 "type": "string",
2470 "const": "const"
2471 },
2472 "value": {
2473 "$ref": "#/$defs/cell_value"
2474 }
2475 }
2476 },
2477 {
2478 "type": "object",
2479 "additionalProperties": false,
2480 "required": [
2481 "codec",
2482 "values"
2483 ],
2484 "properties": {
2485 "codec": {
2486 "type": "string",
2487 "const": "values"
2488 },
2489 "values": {
2490 "type": "array",
2491 "items": {
2492 "$ref": "#/$defs/cell_value"
2493 }
2494 }
2495 }
2496 },
2497 {
2498 "type": "object",
2499 "additionalProperties": false,
2500 "required": [
2501 "codec",
2502 "values",
2503 "indexes"
2504 ],
2505 "properties": {
2506 "codec": {
2507 "type": "string",
2508 "const": "dict"
2509 },
2510 "values": {
2511 "type": "array",
2512 "items": {
2513 "$ref": "#/$defs/cell_value"
2514 }
2515 },
2516 "indexes": {
2517 "type": "array",
2518 "items": {
2519 "type": "integer",
2520 "minimum": 0
2521 }
2522 }
2523 }
2524 }
2525 ]
2526 },
2527 "aggregation_rule": {
2528 "type": "string",
2529 "enum": [
2530 "none",
2531 "first",
2532 "last",
2533 "set",
2534 "count",
2535 "sum",
2536 "min",
2537 "max",
2538 "avg"
2539 ]
2540 },
2541 "layer": {
2542 "type": "string",
2543 "enum": [
2544 "node",
2545 "virtualization",
2546 "container",
2547 "kubernetes",
2548 "process",
2549 "network",
2550 "storage",
2551 "streaming",
2552 "service",
2553 "custom"
2554 ]
2555 },
2556 "color_slot": {
2557 "type": "string",
2558 "enum": [
2559 "primary",
2560 "secondary",
2561 "accent",
2562 "self",
2563 "neutral",
2564 "muted",
2565 "dim",
2566 "derived",
2567 "info",
2568 "structural",
2569 "warning",
2570 "success",
2571 "danger",
2572 "blue",
2573 "green",
2574 "orange",
2575 "purple",
2576 "cyan",
2577 "yellow",
2578 "teal",
2579 "gray"
2580 ]
2581 },
2582 "opacity_token": {
2583 "type": "string",
2584 "enum": [
2585 "normal",
2586 "muted",
2587 "faded"
2588 ]
2589 },
2590 "width_token": {
2591 "type": "string",
2592 "enum": [
2593 "thin",
2594 "normal",
2595 "thick",
2596 "emphasis"
2597 ]
2598 },
2599 "layout_strength_token": {
2600 "type": "string",
2601 "enum": [
2602 "weakest",
2603 "weaker",
2604 "normal",
2605 "stronger",
2606 "strongest"
2607 ]
2608 },
2609 "layout_distance_token": {
2610 "type": "string",
2611 "enum": [
2612 "closest",
2613 "closer",
2614 "normal",
2615 "farther",
2616 "farthest"
2617 ]
2618 },
2619 "actor_size_scale_token": {
2620 "type": "string",
2621 "enum": [
2622 "compact",
2623 "normal",
2624 "emphasized"
2625 ]
2626 },
2627 "link_semantic_role": {
2628 "type": "string",
2629 "enum": [
2630 "normal",
2631 "discovery",
2632 "ownership",
2633 "traffic",
2634 "correlation",
2635 "control"
2636 ]
2637 },
2638 "icon_token": {
2639 "type": "string",
2640 "enum": [
2641 "router",
2642 "switch",
2643 "firewall",
2644 "access_point",
2645 "server",
2646 "storage",
2647 "load_balancer",
2648 "printer",
2649 "phone",
2650 "ups",
2651 "camera",
2652 "process",
2653 "agent",
2654 "netdata-agent",
2655 "parent",
2656 "remote-endpoint",
2657 "local-endpoint",
2658 "segment",
2659 "self",
2660 "ip",
2661 "cloud",
2662 "container",
2663 "vm",
2664 "database",
2665 "service",
2666 "datacenter",
2667 "cluster",
2668 "host",
2669 "network",
2670 "datastore",
2671 "datastore_cluster",
2672 "resource_pool",
2673 "device",
2674 "endpoint",
2675 "correlation",
2676 "interface",
2677 "group",
2678 "unknown"
2679 ]
2680 },
2681 "id": {
2682 "type": "string",
2683 "pattern": "^[A-Za-z][A-Za-z0-9_.:-]*$"
2684 },
2685 "scalar_or_array": {
2686 "anyOf": [
2687 {
2688 "type": "null"
2689 },
2690 {
2691 "type": "boolean"
2692 },
2693 {
2694 "type": "integer"
2695 },
2696 {
2697 "type": "number"
2698 },
2699 {
2700 "type": "string"
2701 },
2702 {
2703 "type": "array",
2704 "items": {
2705 "anyOf": [
2706 {
2707 "type": "null"
2708 },
2709 {
2710 "type": "boolean"
2711 },
2712 {
2713 "type": "integer"
2714 },
2715 {
2716 "type": "number"
2717 },
2718 {
2719 "type": "string"
2720 }
2721 ]
2722 }
2723 }
2724 ]
2725 },
2726 "cell_value": {
2727 "anyOf": [
2728 {
2729 "type": "null"
2730 },
2731 {
2732 "type": "boolean"
2733 },
2734 {
2735 "type": "integer"
2736 },
2737 {
2738 "type": "number"
2739 },
2740 {
2741 "type": "string"
2742 },
2743 {
2744 "type": "array",
2745 "items": {
2746 "$ref": "#/$defs/cell_value"
2747 }
2748 },
2749 {
2750 "type": "object",
2751 "additionalProperties": {
2752 "$ref": "#/$defs/cell_value"
2753 }
2754 }
2755 ]
2756 }
2757 }
2758 }