| 1 | # Spec - Topology Function Schema |
| 2 | |
| 3 | ## Status |
| 4 | |
| 5 | Active for new topology Function work. Existing deployed topology producers are |
| 6 | to be migrated to this contract. |
| 7 | |
| 8 | ## Contract |
| 9 | |
| 10 | Topology Functions return normal Function envelopes with `type: "topology"` and |
| 11 | `data.schema_version: "netdata.topology.v1"`. |
| 12 | |
| 13 | The production schema is defined by: |
| 14 | |
| 15 | - `src/plugins.d/FUNCTION_TOPOLOGY_SCHEMA.json` |
| 16 | - `src/plugins.d/FUNCTION_TOPOLOGY_DEVELOPER_GUIDE.md` |
| 17 | |
| 18 | The schema is generic across topology domains. It applies to network |
| 19 | connections, streaming, SNMP/L2, vSphere, and future topology producers. |
| 20 | |
| 21 | ## Planes |
| 22 | |
| 23 | Topology payloads separate these planes: |
| 24 | |
| 25 | - actors: observed entities such as nodes, processes, containers, ports, |
| 26 | devices, streaming agents, or virtualization objects; |
| 27 | - graph links: renderable relationship groups between actors; |
| 28 | - evidence: canonical relationship facts behind graph links; |
| 29 | - detail tables: actor-owned or relationship-owned drilldown data; |
| 30 | - actor labels: actor-owned key/value rows for modal labels and filters, not a |
| 31 | replacement for canonical identity or grouping columns; |
| 32 | - presentation: backend-selected UI-token composition for labels, colors, |
| 33 | icons, legends, highlighting, link styles, scale keys, and graph port |
| 34 | bullets; |
| 35 | - modal composition: actor/link modal recipes over existing actors, links, |
| 36 | evidence, labels, and detail tables; |
| 37 | - correlation: producer-visible rules, loose-side resolution, replacement, |
| 38 | enrichment, visible correlation points, and claims used by an aggregator to |
| 39 | correlate independently produced topology maps without exposing aggregator |
| 40 | internal states; |
| 41 | - overlay refs: compact references for refreshable metrics or Function-backed |
| 42 | snapshots. |
| 43 | |
| 44 | Graph links are projections. Evidence rows are the facts used by Cloud |
| 45 | aggregation, matching, and detailed drilldowns. |
| 46 | |
| 47 | ## Mode Requests |
| 48 | |
| 49 | Mode requests use `__topology_mode` when a producer has a real detailed vs |
| 50 | aggregated output difference. Valid values are `detailed` and `aggregated`. |
| 51 | Mode-invariant topologies should not expose a selector only to return identical |
| 52 | payloads. Mode-capable producers declare `data.view.supported_modes`; absent |
| 53 | or single-value `supported_modes` means the topology is mode-invariant for UI |
| 54 | control purposes. The Cloud topology aggregator consumes detailed payloads for |
| 55 | mode-capable producers before returning an aggregated view, so producers must |
| 56 | preserve correlation-grade evidence in detailed mode. |
| 57 | |
| 58 | ## Compact Tables |
| 59 | |
| 60 | Large sections use compact columnar tables with: |
| 61 | |
| 62 | - `rows` |
| 63 | - `columns` |
| 64 | - `values` |
| 65 | |
| 66 | Supported column codecs are: |
| 67 | |
| 68 | - `const` |
| 69 | - `values` |
| 70 | - `dict` |
| 71 | |
| 72 | Every decoded column must produce exactly `rows` values. Producers should use |
| 73 | shared helpers for table building, dictionary encoding, validation, and |
| 74 | deterministic sorting rather than hand-rolling encoders in each plugin. |
| 75 | |
| 76 | Column type `json` is allowed only for actor-owned or custom detail cells that |
| 77 | must preserve nested producer-owned values. It is not the default for |
| 78 | relationship evidence, because high-cardinality evidence needs typed scalar, |
| 79 | reference, array, or dictionary-backed columns for compactness and aggregation |
| 80 | semantics. |
| 81 | |
| 82 | ## Identity And Aggregation |
| 83 | |
| 84 | Actor types declare: |
| 85 | |
| 86 | - source-local `identity`; |
| 87 | - cross-payload `merge_identity`; |
| 88 | - optional `parent_identity`; |
| 89 | - supported `aggregation_scopes`. |
| 90 | - optional `search` policy over actor table columns and actor label keys. |
| 91 | - optional `presentation` with UI-owned tokens, safe label policy, size policy, |
| 92 | actor repulsion policy, and graph port-bullet policy. |
| 93 | |
| 94 | Link types declare: |
| 95 | |
| 96 | - `orientation`: `directed`, `undirected`, `hierarchical`, or |
| 97 | `observed_bidirectional`; |
| 98 | - `direction_role`: `none`, `flow`, `dependency`, `ownership`, or |
| 99 | `observation`; |
| 100 | - optional `semantic_role`: `normal`, `discovery`, `ownership`, `traffic`, |
| 101 | `correlation`, or `control`; |
| 102 | - aggregation policy for direction, evidence, metrics, tables, and overlays. |
| 103 | - optional `presentation` with UI-owned color, line style, width, curve, arrow, |
| 104 | tokenized layout strength/distance, and one variable visual channel. |
| 105 | |
| 106 | Port types are optional and declare graph port-bullet presentation only. |
| 107 | Actor/link modal composition is declared separately under actor/link type |
| 108 | presentation and table type presentation. Modal recipes are selectors and |
| 109 | projections over existing facts; they are not duplicate row stores. |
| 110 | |
| 111 | Cloud aggregation may only canonicalize endpoint order when link type policy |
| 112 | explicitly allows unordered aggregation. Direction-significant links must |
| 113 | preserve direction. |
| 114 | |
| 115 | ## Evidence And Tables |
| 116 | |
| 117 | Relationship evidence is not actor custom data. |
| 118 | |
| 119 | Evidence tables carry matchable relationship facts such as socket tuples, |
| 120 | streaming hops, LLDP/CDP observations, or vSphere inventory edges. Actor-detail |
| 121 | tables carry actor-owned data such as streaming path inventory or local status |
| 122 | tables. Table metadata must state role and aggregation policy. |
| 123 | |
| 124 | Production payloads must not duplicate the same evidence under every actor only |
| 125 | to populate drilldown modals. The UI and aggregator derive drilldown views from |
| 126 | shared evidence and typed table references. |
| 127 | |
| 128 | Actor labels use a compact actor-owned table, normally |
| 129 | `tables.actor.actor_labels`, with rows shaped as: |
| 130 | |
| 131 | ```text |
| 132 | actor, key, value, source?, kind?, value_index? |
| 133 | ``` |
| 134 | |
| 135 | `key`, `value`, `source`, and `kind` are logical strings and may be encoded as |
| 136 | `string` or `string_ref`. Producers should prefer `string_ref` when they already |
| 137 | maintain a local dictionary; aggregators and UI adapters must normalize both |
| 138 | encodings as equivalent label strings. |
| 139 | |
| 140 | Host/node actors should expose the complete host label set when available. |
| 141 | Non-node actors should expose useful producer-known labels and metadata, such |
| 142 | as process command line, user, group, namespace, interface role, or |
| 143 | virtualization object properties. Repeated values are repeated rows ordered by |
| 144 | `value_index`, not JSON arrays. Facts needed for identity, correlation, |
| 145 | grouping, sorting, filtering, or aggregation must remain typed canonical |
| 146 | columns too. |
| 147 | |
| 148 | `actor_labels` inherits the topology Function sensitive-data classification. |
| 149 | Consumers must preserve the same access-control assumptions as the source |
| 150 | Function because labels may include command lines, users, host labels, system |
| 151 | contact/location fields, or other operator-controlled metadata. |
| 152 | |
| 153 | Actor modal identification is producer-selected through |
| 154 | `presentation.modal.labels.identification.fields[]`. Each field references an |
| 155 | existing `actor_labels.key`, provides the label to render near the actor title, |
| 156 | and may limit the number of displayed values with `max_values`. The full Labels |
| 157 | tab remains complete; identification is a curated header projection, not a |
| 158 | second table. |
| 159 | |
| 160 | ## Presentation |
| 161 | |
| 162 | Presentation belongs in the production `netdata.topology.v1` payload, not in |
| 163 | Function `info`, except for old-schema compatibility during rollout. |
| 164 | |
| 165 | Function `info` responses are metadata responses. They may omit `data` and |
| 166 | advertise only parameters, help text, and timing. The topology JSON schema |
| 167 | applies to full topology responses, not metadata-only `info` responses. |
| 168 | |
| 169 | Type definitions carry type-local presentation: |
| 170 | |
| 171 | - `types.actor_types.<id>.presentation` |
| 172 | - `types.link_types.<id>.presentation` |
| 173 | - `types.port_types.<id>.presentation` |
| 174 | |
| 175 | Graph-level `data.presentation` carries legend order, actor-click highlight |
| 176 | behavior, port tooltip field labels, and scale-key definitions. |
| 177 | |
| 178 | Actor and link type presentation may also carry modal composition: |
| 179 | |
| 180 | - `presentation.modal.labels` describes the actor label table, usually |
| 181 | `actor_labels`; |
| 182 | - `presentation.modal.mini_topology` describes a depth-1 modal graph preview |
| 183 | built from incident links and opposite actors; |
| 184 | - `presentation.modal.sections[]` describes table sections over existing |
| 185 | actors, links, evidence, actor detail tables, or relationship tables. |
| 186 | |
| 187 | Table types may carry `presentation` defaults for table label, order, default |
| 188 | visibility, and column display metadata. Table type presentation does not |
| 189 | replace actor/link modal sections; it gives reusable defaults for existing |
| 190 | table rows. |
| 191 | |
| 192 | Modal sections require non-empty `id`, non-empty `label`, a source, and at |
| 193 | least one column. `empty_label` is section-only empty-state text. Modal columns |
| 194 | require non-empty `id`, non-empty `label`, and a projection. `badge_map`, |
| 195 | `align`, and `sortable` are presentation hints over projected values and must |
| 196 | not introduce new facts. |
| 197 | |
| 198 | `label_lookup` uses `label_key` and optionally an `actor_column`; omitted |
| 199 | `actor_column` means the selected modal actor. `json_path` always requires both |
| 200 | the JSON `column` and the scalar `path` to extract. |
| 201 | |
| 202 | Presentation uses closed UI-owned tokens. Producers must not emit raw SVG, raw |
| 203 | CSS, coordinates, component names, raw force-layout physics, or viewport state. |
| 204 | |
| 205 | Closed token values are part of the schema contract: |
| 206 | |
| 207 | - color slots: `primary`, `secondary`, `accent`, `self`, `neutral`, `muted`, |
| 208 | `dim`, `derived`, `info`, `structural`, `warning`, `success`, `danger`, |
| 209 | `blue`, `green`, `orange`, `purple`, `cyan`, `yellow`, `teal`, `gray`; |
| 210 | - opacity tokens: `normal`, `muted`, `faded`; |
| 211 | - width tokens: `thin`, `normal`, `thick`, `emphasis`; |
| 212 | - link layout strength tokens: `weakest`, `weaker`, `normal`, `stronger`, |
| 213 | `strongest`; |
| 214 | - link layout distance tokens: `closest`, `closer`, `normal`, `farther`, |
| 215 | `farthest`; |
| 216 | - actor layout repulsion tokens: `weakest`, `weaker`, `normal`, `stronger`, |
| 217 | `strongest`; |
| 218 | - actor size scale tokens: `compact`, `normal`, `emphasized`; |
| 219 | - link semantic roles: `normal`, `discovery`, `ownership`, `traffic`, |
| 220 | `correlation`, `control`; |
| 221 | - icons: `router`, `switch`, `firewall`, `access_point`, `server`, `storage`, |
| 222 | `load_balancer`, `printer`, `phone`, `ups`, `camera`, `process`, `agent`, |
| 223 | `netdata-agent`, `parent`, `remote-endpoint`, `local-endpoint`, `segment`, |
| 224 | `self`, `ip`, `cloud`, `container`, `vm`, `database`, `service`, |
| 225 | `datacenter`, `cluster`, `host`, `network`, `datastore`, |
| 226 | `datastore_cluster`, `resource_pool`, `device`, `endpoint`, `correlation`, |
| 227 | `interface`, `group`, `unknown`. |
| 228 | |
| 229 | The UI owns token rendering and must treat producer labels as plain text. If a |
| 230 | new producer emits a schema-valid token that an older UI does not know, the UI |
| 231 | must use a safe fallback and record diagnostics. |
| 232 | |
| 233 | Actor `label_policy` is the only approved way to choose display labels from |
| 234 | actor rows. Canonical identity is not display text. The UI must reject array |
| 235 | values by default so aggregated identities do not become long actor names. |
| 236 | Label-policy columns must be safe scalar actor-table columns. Producers must |
| 237 | not reference secrets, tokens, customer-identifying fields, or unbounded arrays |
| 238 | from `label_policy.columns`. |
| 239 | |
| 240 | Actor `search` is the only approved way to choose graph search content for v1. |
| 241 | `search.columns[]` references scalar actor-table columns. `search.label_keys[]` |
| 242 | references values in the actor label table, normally `actor_labels.key`. Set |
| 243 | `search.enabled: false` for helper actors that should not be searchable. The UI |
| 244 | must not traverse producer-specific `details`, `match`, `attributes`, or label |
| 245 | paths when rendering v1. |
| 246 | |
| 247 | Link types may define one variable visual channel using `variable.channel`, |
| 248 | `variable.scale_key`, and `variable.value_column`. Producers emit raw domain |
| 249 | values, such as socket counts or traffic bytes. Cloud or the UI scales values |
| 250 | per `scale_key` across the visible graph. `variable.min` and `variable.max` |
| 251 | are visual tokens for the chosen channel: width variables use width tokens, |
| 252 | opacity variables use opacity tokens. |
| 253 | |
| 254 | Link types may also define tokenized force-layout hints using |
| 255 | `presentation.layout.strength` and `presentation.layout.distance`. These are |
| 256 | relative UI-owned tokens, not numeric physics. Current producer tuning keeps |
| 257 | `strength` at `normal` and varies only `distance` where the topology needs |
| 258 | semantic separation. Do not reintroduce non-normal `strength` tokens for graph |
| 259 | polish unless a later product decision explicitly re-enables force-strength |
| 260 | tuning. |
| 261 | |
| 262 | Actor types may define tokenized force-layout hints using |
| 263 | `presentation.layout.repulsion`. Repulsion is separate from link strength: |
| 264 | repulsion pushes actors apart, while link strength pulls endpoints together. |
| 265 | Producers must not emit raw charge values. Actor size may define a type-level |
| 266 | `size.scale` token for deliberate fixed emphasis, such as current/self actors; |
| 267 | the UI must not infer this from actor type names or labels. |
| 268 | |
| 269 | `link_types.<id>.semantic_role` is behavior metadata, not visual styling. It |
| 270 | drives UI behavior such as discovery-link filtering, ownership/coherence |
| 271 | treatment, traffic emphasis, and correlation treatment without hardcoded |
| 272 | protocol or type-name checks. Link appearance still comes from |
| 273 | `presentation`. |
| 274 | |
| 275 | When link `presentation.arrow` is `auto` or omitted, the UI derives arrows from |
| 276 | `orientation` and `direction_role`: |
| 277 | |
| 278 | - `undirected` -> no arrow; |
| 279 | - `observed_bidirectional` -> no arrow; |
| 280 | - `direction_role: none` -> no arrow; |
| 281 | - `direction_role: observation` -> no arrow; |
| 282 | - `directed` with `flow` or `dependency` -> forward from `src_actor` to |
| 283 | `dst_actor`; |
| 284 | - `hierarchical` with `ownership` -> forward from `src_actor` to `dst_actor`; |
| 285 | - all other combinations -> no arrow and a diagnostic if the combination is |
| 286 | schema-valid but semantically unusual. |
| 287 | |
| 288 | `observed_bidirectional` means observation completeness, not "draw both |
| 289 | arrows". Producers that need reverse or both arrows must set |
| 290 | `presentation.arrow` explicitly. |
| 291 | |
| 292 | `direction_role` is required by the v1 schema. Missing `direction_role` is |
| 293 | schema-invalid and must not produce an inferred arrow from `orientation` alone. |
| 294 | The UI should render `auto` as no arrow and emit the normal missing-field |
| 295 | diagnostic for that invalid input. |
| 296 | |
| 297 | For schema-valid values, the `auto` semantic diagnostic boundary is: |
| 298 | |
| 299 | - no diagnostic for `directed+flow`, `directed+dependency`, |
| 300 | `hierarchical+ownership`, `undirected+none`, `undirected+observation`, |
| 301 | `observed_bidirectional+none`, or `observed_bidirectional+observation`; |
| 302 | - diagnostic for `directed+none`, `directed+observation`, |
| 303 | `directed+ownership`, `hierarchical+none`, `hierarchical+flow`, |
| 304 | `hierarchical+dependency`, `hierarchical+observation`, `undirected+flow`, |
| 305 | `undirected+dependency`, `undirected+ownership`, |
| 306 | `observed_bidirectional+flow`, `observed_bidirectional+dependency`, or |
| 307 | `observed_bidirectional+ownership`. |
| 308 | |
| 309 | Initial UI-owned mappings are: |
| 310 | |
| 311 | - `size.scale`: `compact=0.85`, `normal=1.0`, `emphasized=1.18`; |
| 312 | - `layout.repulsion`: `weakest=-200`, `weaker=-300`, `normal=-450`, |
| 313 | `stronger=-700`, `strongest=-1000`. |
| 314 | |
| 315 | These numeric values are not schema and may be tuned after visual QA. |
| 316 | `size.scale` composes with `size.mode`; it does not override data-driven |
| 317 | sizing. Missing optional fields use neutral defaults (`scale: normal`, |
| 318 | `repulsion: normal`) and must not trigger v1 UI fallback heuristics. |
| 319 | |
| 320 | Actor port bullets require explicit `ports.sources[]` when |
| 321 | `show_bullets: true`. The source may be `links`, `evidence`, or an |
| 322 | `actor_table`. Source column names are table-local and must remain unchanged |
| 323 | during Cloud aggregation. Type ids inside row values and `default_type` values |
| 324 | are rewritten only when they refer to type registries. `ports.sources[].evidence` |
| 325 | is an evidence type id. `name_column` must reference a scalar display column, |
| 326 | not a raw actor/link/evidence reference, array, or JSON cell. |
| 327 | `ports.sources[].value_column` is optional and must reference a numeric source |
| 328 | column. When present, the UI sums values for matching bullet keys and uses the |
| 329 | sum for bullet multiplicity, overflow, and sizing. Aggregated producers should |
| 330 | use this instead of sending repeated rows only to drive presentation. |
| 331 | |
| 332 | Modal/table composition uses closed source, projection, cell, and visibility |
| 333 | tokens. Supported source kinds are `actors`, `links`, `evidence`, |
| 334 | `actor_table`, and `relationship_table`. Supported projections include direct |
| 335 | column values, actor-ref labels, opposite actor labels, formatted endpoints, |
| 336 | selected-side endpoints, label-table lookups, coalesced columns, constants, |
| 337 | and explicitly declared scalar JSON paths. Supported cell types include text, |
| 338 | number, badge, actor link, timestamp, duration, endpoint, array count, and |
| 339 | debug JSON. Raw JSON belongs behind `debug` visibility or an explicit scalar |
| 340 | projection; it must not be the default polished actor modal rendering. |
| 341 | Selected-side endpoint projections must be self-contained: the projection |
| 342 | names source and destination actor-ref columns, plus at least one source-side |
| 343 | endpoint column and one destination-side endpoint column. |
| 344 | |
| 345 | `selection.actor_click.mode: highlight_path` requires `path_table`, |
| 346 | `path_actor_column`, and `path_order_column`. `path_actor_column` identifies |
| 347 | path members. When one table contains different paths for different clicked |
| 348 | actors, `path_owner_column` identifies the actor that owns each path row. |
| 349 | `highlight_connections` requires no path table. |
| 350 | |
| 351 | Presentation conflict policy: |
| 352 | |
| 353 | - producer-local type ids, port ids, scale keys, evidence ids, table type ids, |
| 354 | and overlay template ids are namespaced before aggregation; |
| 355 | - identical definitions are deduplicated after canonicalization; |
| 356 | - conflicting local definitions are preserved as distinct canonical ids rather |
| 357 | than hard-failing aggregation; |
| 358 | - `label_policy` belongs to the actor type presentation and follows the same |
| 359 | namespace/deduplicate rule; |
| 360 | - `profile_version` is diagnostic. It may help choose a preferred display |
| 361 | profile later, but it is not a comparable semantic-version contract and must |
| 362 | not be used to drop facts or rows. |
| 363 | |
| 364 | ## Correlation Contract |
| 365 | |
| 366 | Correlation is producer-visible graph semantics, not aggregator state. |
| 367 | Producers must not encode correlation as hidden flags on real actors, and must |
| 368 | not expose aggregator internal states such as absorbed, candidate, equivalence |
| 369 | class, or rewrite plan. The final aggregated output is always a normal topology |
| 370 | payload. |
| 371 | |
| 372 | Correlation can resolve several shapes: |
| 373 | |
| 374 | - loose relationship sides, where one side of a detailed row has endpoint facts |
| 375 | but no known actor; |
| 376 | - visible correlation actors, where the input graph intentionally materializes |
| 377 | unresolved peers; |
| 378 | - weaker placeholder actors that should be replaced by stronger managed actors; |
| 379 | - equivalent actors that should be merged and enriched with facts from multiple |
| 380 | payloads. |
| 381 | |
| 382 | `data.correlation.rules` defines how independent payloads of the same topology |
| 383 | kind can be correlated. Each rule defines: |
| 384 | |
| 385 | - optional `class`: `resolve_loose_side`, `replace_actor`, or |
| 386 | `merge_enrich_actor`; |
| 387 | - `action`: `absorb` for exact matches that remove visible correlation actors |
| 388 | or consume loose-side placeholders and rewrite incident correlation |
| 389 | relationships, or `link` for partial/broader matches that keep the visible |
| 390 | correlation/materialized actor and add a weak correlation link; |
| 391 | - `priority`: lower numbers run first; |
| 392 | - `key_space`: namespace for exact string-key matching; |
| 393 | - `key`: a declarative template built from point/claim table columns and |
| 394 | literals; |
| 395 | - `point_actor_types`: actor types that are visible correlation points when the |
| 396 | input graph materializes points; |
| 397 | - optional `claim_actor_types`: actor types that may satisfy the point; |
| 398 | - optional `correlation_link_types`: link types that connect real actors to |
| 399 | correlation actors and may be consumed/replaced by the rule; |
| 400 | - `output_link_type`: link type emitted for rewritten absorb links or visible |
| 401 | partial correlation links. |
| 402 | |
| 403 | `data.correlation.points` is a compact table of visible correlation actors and keys. |
| 404 | `data.correlation.claims` is a compact table of real actors and keys they can |
| 405 | satisfy. Both tables require `actor`, `rule`, and the key columns referenced by |
| 406 | their rules. |
| 407 | |
| 408 | The aggregator is intentionally agnostic. It builds normalized keys from |
| 409 | declared columns and literals, applies rule priority, and handles ambiguity |
| 410 | conservatively. It must not need new code to understand every future IP, port, |
| 411 | MAC, chassis id, object id, label, or topology-domain key. |
| 412 | |
| 413 | No match keeps the visible correlation actor or loose-side materialization |
| 414 | visible. Ambiguous matches remain unresolved and produce diagnostics. NAT or |
| 415 | other alias evidence can be modeled by adding extra point/claim rows for the |
| 416 | same actor and rule; aliases add facts without mutating the original |
| 417 | observation. |
| 418 | |
| 419 | Correlation links must be semantic link types even for single-node payloads. |
| 420 | The legend must include visible correlation actors and links when they are |
| 421 | visible, so users can distinguish unresolved, partial, inferred, and resolved |
| 422 | graph relationships. |
| 423 | |
| 424 | ## Telemetry Overlays |
| 425 | |
| 426 | Refreshable traffic, state, error, packet, or utilization data is represented by |
| 427 | overlay templates and per-actor/per-link refs. |
| 428 | |
| 429 | Templates define the query mechanism once. Refs provide only template ids, one |
| 430 | owner reference, and selector parameters. The refs table uses schema ids for |
| 431 | column names, so template ids, selector params, and refs column ids must match |
| 432 | the topology `$defs/id` contract: start with a letter and then use only letters, |
| 433 | digits, `_`, `.`, `:`, or `-`. |
| 434 | |
| 435 | The refs-table convention is: |
| 436 | |
| 437 | - `template`: string or string_ref template name resolving to |
| 438 | `data.types.overlay_templates`; |
| 439 | - exactly one convention owner column: `actor` with type `actor_ref` or `link` |
| 440 | with type `link_ref`; every row must have a non-null owner value; |
| 441 | - one column for each selector param required by the referenced template. |
| 442 | |
| 443 | Selector params must not use reserved refs-table convention column names: |
| 444 | `template`, `actor`, or `link`. |
| 445 | |
| 446 | No other `actor_ref` or `link_ref` columns are valid in overlay refs. Consumers |
| 447 | can identify ownership from the fixed `actor` / `link` column ids instead of |
| 448 | scanning all columns by type. |
| 449 | |
| 450 | The `template` column and all selector-param columns required by a row's |
| 451 | resolved template must be `string` or `string_ref`. Required selector-param row |
| 452 | values must resolve to non-empty strings. Selector-param columns used by other |
| 453 | templates may be nullable and null on rows whose template does not require them. |
| 454 | Future selectors that need `ip_ref`, `mac_ref`, or empty-string matching must |
| 455 | relax this contract explicitly. |
| 456 | |
| 457 | For `provider: "netdata.metrics"`, selector params are interpreted as: |
| 458 | |
| 459 | - `node_id`: node-scope selector, not a chart label; |
| 460 | - `collect_job`: chart label `_collect_job`; |
| 461 | - other params: same-named chart labels. |
| 462 | |
| 463 | Aggregated actors or links merge overlay refs according to the template merge |
| 464 | policy. `merge.refs` controls ref-list handling, currently `append` or `set`. |
| 465 | `merge.values` controls how multiple matching metric values collapse, currently |
| 466 | `sum`, `min`, `max`, `avg`, `last`, or `none`. |
| 467 | |
| 468 | ## Compatibility |
| 469 | |
| 470 | Production payloads carry canonical topology facts, not compatibility |
| 471 | reconstruction instructions. Projection code for parity with deployed |
| 472 | compatibility consumers is test or rollout code only. |
| 473 | |
| 474 | Agent/backend contracts and docs should point new work to |
| 475 | `netdata.topology.v1`. Temporary compatibility handling belongs in isolated |
| 476 | Cloud frontend adapters during rollout. |
| 477 | |
| 478 | ## Validation |
| 479 | |
| 480 | Topology producer changes must include: |
| 481 | |
| 482 | - JSON Schema validation against `FUNCTION_TOPOLOGY_SCHEMA.json`; |
| 483 | - semantic validation for table column lengths and reference bounds; |
| 484 | - fixture or corpus tests for payload size and evidence preservation; |
| 485 | - tests proving direction and aggregation policy are honored; |
| 486 | - checks that evidence is not silently truncated. |
| 487 | |
| 488 | Cloud topology aggregation service readiness also requires service-level |
| 489 | fixtures for every topology kind covered by this contract. `network-connections` |
| 490 | is the high-cardinality benchmark, but the service is not considered ready if |
| 491 | the UI can use it for only some topology kinds while bypassing it for others. |
| 492 | |
| 493 | ## Migration Notes |
| 494 | |
| 495 | `topology:network-connections` now emits `netdata.topology.v1` directly from |
| 496 | the C network-viewer Function. Aggregated mode is the default and emits compact |
| 497 | actor, graph-link, and actor-owned `socket_ports` tables. Detailed mode adds a |
| 498 | shared socket relationship-evidence table for exact tuple matching and |
| 499 | drilldowns. Process actor size uses the actor row `socket_count` metric, while |
| 500 | process port bullets read the `socket_ports.socket_count` value column so an |
| 501 | aggregated port row can represent several sockets. The producer no longer emits |
| 502 | the superseded old-schema presentation object or duplicated actor-nested socket |
| 503 | modal tables. It now emits compact graph presentation metadata in type |
| 504 | definitions plus `data.presentation`, and repeated string columns use |
| 505 | dictionary encoding when it reduces raw payload size. |
| 506 | |
| 507 | Network-connections distinguishes unresolved endpoint links from aggregator |
| 508 | correlation output. `endpoint_socket` connects a process to a visible unresolved |
| 509 | endpoint actor and must not use the farthest layout distance because that makes |
| 510 | single-node maps zoom out unnecessarily. `correlated_socket` is the output link |
| 511 | type after exact endpoint absorption by an aggregator and may use farthest |
| 512 | distance to keep independent topology clusters from blending. |
| 513 | |
| 514 | Network-connections modal composition is producer-declared. Self/node actors use |
| 515 | a `Processes` section over `ownership` graph links filtered by link type. |
| 516 | Network-connections socket link types use `direction_role: "dependency"` and |
| 517 | are client-to-server: `src_actor` is the client/dependant and `dst_actor` is the |
| 518 | server/dependency target. Non-node actors therefore use two primary sections in |
| 519 | both aggregated and detailed mode: |
| 520 | `Dependencies`, filtered to rows where the selected actor is `src_actor`, and |
| 521 | `Dependants`, filtered to rows where the selected actor is `dst_actor`. |
| 522 | Aggregated mode reads these sections from `tables.relationship.connections`; |
| 523 | detailed mode reads them from `evidence.socket`. `socket_ports` is an actor |
| 524 | inventory for process port bullets only; it is not a standalone modal tab for |
| 525 | network-connections. |
| 526 | |
| 527 | `topology:snmp` now emits `netdata.topology.v1` from the Function handler |
| 528 | through an adapter over the existing SNMP topology engine output. The adapter |
| 529 | preserves actors, links, L2 observation evidence, actor metadata, and actor |
| 530 | custom detail tables. Remaining SNMP refinement is to promote interface metric |
| 531 | lookup fragments into first-class overlay templates/refs. |
| 532 | |
| 533 | SNMP modal composition must be port-centric for managed device actors. A managed |
| 534 | device modal uses actor-label identification for important device facts, a |
| 535 | primary `Ports` section over `actor_ports`, and a `Port Neighbors` section over |
| 536 | `actor_port_links`. Generic graph-link `Links` sections are reserved for |
| 537 | endpoint, segment, or custom actors that do not own port inventory. |
| 538 | |
| 539 | SNMP `actor_ports` exposes real port identity and status as typed columns: |
| 540 | SNMP `if_index` as the visible numeric port ID when known, source `port_id`, |
| 541 | display `name`, `if_name`, `if_descr`, `if_alias`, MAC, speed, status, mode, |
| 542 | role, VLAN, FDB, link, and neighbor counts. It must never fabricate numeric |
| 543 | port IDs; row order and generated sequences must not be used. `if_index` must |
| 544 | come from the device/SNMP facts and must align with `actor_port_links.if_index`. |
| 545 | |
| 546 | SNMP `actor_ports` may also carry compact expanded-row neighbor columns such as |
| 547 | nullable `neighbor_actor` and `neighbor_port_name`, derived from graph-link |
| 548 | endpoint facts. These columns make the port row clickable without duplicating |
| 549 | raw LLDP/CDP/FDB/ARP/STP evidence. |
| 550 | |
| 551 | SNMP `actor_port_links` is a compact actor-owned modal index over existing graph |
| 552 | links and evidence. It has one row per incident actor side and carries the local |
| 553 | `if_index`/port name, remote actor, remote port facts, protocol, link type, |
| 554 | state, evidence count, confidence, inference, attachment mode, and timestamps. |
| 555 | It exists so device modals can align neighbor rows with the same port identity |
| 556 | shown in `actor_ports`; it is not a second copy of raw evidence. |
| 557 | |
| 558 | SNMP polished UI must not depend on raw `actor_metadata` and endpoint JSON. |
| 559 | Important scalar/count summary values live in typed actor or actor-detail |
| 560 | columns and are also available through `actor_labels`. Nested neighbors, VLANs, |
| 561 | unknown custom port attributes, and endpoint objects stay in expanded or debug |
| 562 | sections unless a structured child table is defined. Link endpoint port labels |
| 563 | must come only from real port fields such as `port_name`, `if_name`, |
| 564 | `if_descr`, or source `port_id`; actor labels such as `display_name` or |
| 565 | `sys_name` must not be used as port-name fallbacks. |
| 566 | |
| 567 | `topology:streaming` now emits `netdata.topology.v1` directly from the C |
| 568 | Function. It models streaming agents as compact actor rows, streaming/virtual/ |
| 569 | stale relationships as directed graph links with matching evidence types, and |
| 570 | keeps `stream_path`, retention, inbound, and outbound modal data as typed |
| 571 | actor-detail or relationship-summary tables. Streaming also emits graph |
| 572 | presentation metadata for highlight-path behavior, legend, link styles, and |
| 573 | port bullets. Streaming hops remain signed so stale path values are not |
| 574 | corrupted. |
| 575 | |
| 576 | Streaming parent actor size is data-driven by the actor row |
| 577 | `retained_node_count` metric, not by graph degree or direct child count. This |
| 578 | count represents nodes for which the parent has retained DB data, including |
| 579 | self, virtual nodes, stale nodes, and transit descendants when they have |
| 580 | retention state. The parent actor type must declare `presentation.size: |
| 581 | {"mode":"metric","metric_column":"retained_node_count"}`. Parent port bullets |
| 582 | represent child or vnode streams attached to the parent side of streaming graph |
| 583 | links, so the parent `ports.sources[]` entry over `links` must use |
| 584 | `actor_column: "dst_actor"` with a scalar child/node display column such as |
| 585 | `port_name`. |
| 586 | |
| 587 | Streaming modal composition emits `actor_labels`, complete host labels where |
| 588 | available, host/system metadata labels needed by old summaries, and typed |
| 589 | OS/architecture/CPU columns. The actor modal header must select important |
| 590 | identity/status labels from `actor_labels`, including hostname, node type, |
| 591 | stream status, ingest status, health status, retained-node count where |
| 592 | applicable, direct-child count where applicable, OS/platform labels, and Agent |
| 593 | version. Existing `stream_path`, `retention`, and `inbound` tables have the |
| 594 | right actor-ref shape for recipe-based table rendering. The `outbound` table |
| 595 | must use the parent-owned shape described below; a table that only records the |
| 596 | selected actor's own upstream destination is insufficient for parent operator |
| 597 | workflows. |
| 598 | |
| 599 | Streaming actor modal identification is role-specific. Host-like actors |
| 600 | (`parent`, `child`, and `stale`) should expose operational status plus |
| 601 | OS/hardware/platform labels such as OS, OS version, kernel, architecture, CPU |
| 602 | model, cores, RAM, virtualization, container, cloud provider/type/region, and |
| 603 | Agent version. Parents additionally expose `retained_node_count` and |
| 604 | `child_count` so the visual size and direct attachments are both explainable. |
| 605 | Vnode actors should expose inventory/device labels such as vnode type, vendor, |
| 606 | model, address, location, sys object id, LLDP system name, and status. Long |
| 607 | stable identifiers such as `machine_guid` and `node_id` remain in the full |
| 608 | Labels tab by default unless a future product decision explicitly promotes them. |
| 609 | |
| 610 | Streaming actor modals must keep those tables as the single source of truth and |
| 611 | must not duplicate rows only for modal display. The default visible sections are: |
| 612 | |
| 613 | - `Stream path`: rows from `stream_path` filtered by `actor`, ordered by |
| 614 | `path_index`. The table shows the selected actor's own path only; virtual |
| 615 | nodes and children have their own actors and therefore their own path rows. |
| 616 | `since` and `first_time` must be populated from the best canonical source |
| 617 | available for every path row. Synthetic path rows added only for rendering or |
| 618 | highlighting must still carry timestamps when the producer can derive them |
| 619 | from the adjacent path edge, the selected actor's ingest status, or database |
| 620 | first-time status. They may be null only when the Agent genuinely does not |
| 621 | know the value. |
| 622 | - `Retained nodes`: rows from the same `retention` table filtered by |
| 623 | `observer_actor`; this view answers which nodes' data the selected actor |
| 624 | maintains. The table must include self, virtual nodes, direct children, |
| 625 | transit descendants, and stale/archived hosts when those hosts are present in |
| 626 | the Agent root index and have retention state. It must show retained node, |
| 627 | node type, retention status, from/to timestamps, duration, metrics, instances, |
| 628 | and contexts. `db_from` and `db_to` may be null only when the database status |
| 629 | genuinely has no time range. |
| 630 | - `Received nodes`: rows from `inbound` filtered by `parent_actor`; this view |
| 631 | represents children, virtual nodes, stale nodes, and descendants received or |
| 632 | transiting through the selected parent. `source_actor` is the immediate actor |
| 633 | from which the selected parent receives the row. For direct local receipt, |
| 634 | `source_actor` should be the child/vnode actor itself; it should be null only |
| 635 | when the immediate source is genuinely unknown. |
| 636 | - `Outbound streams`: rows from `outbound` filtered by the sending parent |
| 637 | actor, not by the streamed node actor. This view answers which node payloads |
| 638 | the selected parent currently streams, and where it streams each one. Each row |
| 639 | must include the streamed node actor, destination actor when known, status, |
| 640 | age, hops, TLS, compression, and useful stream/replication/count metrics when |
| 641 | available. In clustered-parent setups, the selected parent must list self, |
| 642 | virtual nodes, direct children, and transit descendants that are sent to each |
| 643 | upstream destination. |
| 644 | |
| 645 | The old `Retention for node` default section is not part of the current |
| 646 | streaming modal contract. The canonical `retention` table still keeps both |
| 647 | `actor` and `observer_actor` so Cloud aggregation can preserve multiple |
| 648 | retaining parents for the same node. If a future modal needs a selected-node |
| 649 | "who retains me" view, it must be explicitly named `Retained by` and must not |
| 650 | replace the parent-owned `Retained nodes` view. |