Skip to Content
This documentation is provided with the HEAT environment and is relevant for this HEAT instance only.
GuidesSession TemplatesCapture identity lanes

Capture identity lanes

Multi-user simulation capture sends frames from several capture instances (origin_uuid) and several simulation entities (crew, vehicles, roles). UUIDs and entity IDs differ on every session, so a session template cannot hard-code them.

system-protobuf-extract maintains a session-scoped captureIdentity registry in session metadata and supports filters so parallel DAG branches (lanes) always process the same logical participant within a session.

The problem

Without stable indices:

  • Lane “process pilot events” cannot be authored with a fixed entity_id or origin_uuid.
  • Downstream Arbex must scan all entities every run to find names.
  • Multi-user SIM templates become fragile copy-paste graphs.

The solution

  1. One registry node observes all origins and entities and writes captureIdentity to session metadata.
  2. Lane nodes use filterEntityIndex / filterOriginIndex (or exact uuid/id/name) so each branch emits only one participant’s records.
  3. Indices are first-seen: the first origin or entity observed in the session gets index 0, the next new identity gets index 1, and indices never change for that session.

Session metadata shape

After extract runs, session metadata includes:

{ "captureIdentity": { "version": 1, "ordering": "first_seen", "updatedAtUtc": "2026-07-10T12:00:00.000Z", "origins": [ { "index": 0, "originUuid": "…", "firstSeenAtMs": 1726000000000 } ], "entities": [ { "index": 0, "entityId": 42, "name": "Pilot-1", "firstSeenAtMs": 1726000000001 } ] } }

Inspect this in Cluster Manager session metadata or via Core API session GET. Lane nodes resolve filterEntityIndex: 0 to entityId 42 for the rest of the session.

Template recipe

NodeConfig highlightsRole
extract-identityextractionTarget: EntityState, updateSessionCaptureIdentity: trueSingle writer for captureIdentity
extract-lane-0extractionTarget: EntityDataEvent, filterEntityIndex: 0, updateSessionCaptureIdentity: falseLane for first entity
extract-lane-1filterEntityIndex: 1, updateSessionCaptureIdentity: falseLane for second entity (empty if session has one entity)

Rules:

  • Only one node per session should set updateSessionCaptureIdentity: true (session metadata updates are last-write-wins).
  • Lane nodes default updateSessionCaptureIdentity: false when using index filters.
  • Fixed lane count in the template (e.g. four crew stations). Unused lanes emit zero records; that is normal.

Shipped example: preset heat-capture-mainline-scoped.

Filter reference

All filters are optional; multiple filters combine with AND semantics.

ConfigMatches
filterOriginUuidExact packet origin_uuid
filterOriginIndexcaptureIdentity.origins[index]
filterEntityIdSimulation entity_id on the record
filterEntityIndexcaptureIdentity.entities[index] (lane index)
filterEntityNameExact entity name (case-sensitive)

If a lane runs before the registry has assigned an index, filterEntityIndex / filterOriginIndex match nothing until a later incremental run (lanes warm up during live capture).

Record fields

Extract records include enrichment for downstream binding:

FieldWhen present
origin_uuidAlways (packet envelope)
origin_indexAfter origin observed in registry
entity_idEntityState / EntityDataEvent rows
entity_nameWhen known from frame or registry
entity_indexAfter entity observed in registry

vs capture-discovery

capture-discoverycaptureIdentity
PurposeOperator debug dashboard (what arrived?)Mainline lane routing
OrderingRanked by observation countFirst-seen stable index
Output$heat-dataservice artefactSession metadata JSON
Blocks mainline?No (leaf branch)No (metadata side effect)

Use both: discovery as a leaf, identity registry on the mainline.