Skip to content

Mission Metadata

Mission metadata is an optional core feature for carrying richer event context beside the NATS payload. It is designed for mission-oriented deployments, but it is not defence-only. The same mechanism can describe industrial telemetry, critical infrastructure events, operational reporting, logistics movements, security monitoring, or any workflow where messages need a small, validated context object that should travel consistently to every sink.

The feature is disabled by default. When enabled, the core runtime resolves a validated JSON object before a sink receives the message. Oracle can store the object in a configurable JSON column, the file sink includes it in the emitted JSON record, and future sinks should preserve the same object where their destination contract supports structured metadata.

flowchart LR
    P[Publisher] -->|payload + optional header| JS[JetStream]
    JS --> R[JetStreamSinkRunner]
    R --> V[Validate mission metadata]
    V --> E[NatsEnvelope.mission_metadata]
    E --> O[Oracle MISSION_METADATA_JSON]
    E --> F[File record mission_metadata]
    V -->|invalid| DLQ[DLQ before ACK]

Why It Exists

Fixed columns are useful for stable framework-wide metadata such as priority, classification, and labels. They become a poor fit when each deployment wants different context fields: mission identifiers, operation identifiers, platform IDs, source-system IDs, track IDs, correlation IDs, confidence values, releasability markers, domain labels, or use-case-specific phase markers such as F2T2EA.

Mission metadata solves that by providing one generic JSON object:

  • the core validates it once,
  • every sink sees the same normalized object,
  • Oracle stores it as one JSON value instead of many fixed columns,
  • file sink records include the same object,
  • invalid metadata follows normal permanent-failure handling.

Configuration

Mission metadata is configured at the top level of the JSON config file:

{
  "mission_metadata": {
    "enabled": true,
    "header": "Nats-Sinks-Mission-Metadata",
    "max_bytes": 8192,
    "allowed_profiles": ["mission-event-v1"],
    "profiles": [
      {
        "name": "mission-event-v1",
        "version": 1,
        "unknown_fields": "forbid",
        "required_fields": [
          {"name": "event_id", "type": "string", "max_length": 128},
          {"name": "source_system", "type": "string", "max_length": 128}
        ],
        "optional_fields": [
          {
            "name": "f2t2ea_phase",
            "type": "string",
            "enum": ["find", "fix", "track", "target", "engage", "assess"]
          },
          {"name": "origin_domain", "type": "string", "max_length": 128}
        ]
      }
    ],
    "default": {
      "profile": "mission-event-v1",
      "profile_version": 1,
      "event_id": "default-event",
      "source_system": "operator-default",
      "origin_domain": "operations"
    },
    "rules": [
      {
        "subject": "mission.synthetic.>",
        "metadata": {
          "profile": "mission-event-v1",
          "profile_version": 1,
          "event_id": "synthetic-default",
          "origin_domain": "synthetic-test",
          "source_system": "local-harness"
        }
      }
    ]
  }
}
Field Required Default Valid values Description
enabled no false true or false Turns mission metadata parsing on. Disabled runners ignore the configured header.
header no Nats-Sinks-Mission-Metadata Non-empty header name without control characters. Header containing a JSON object supplied by the publisher.
max_bytes no 8192 Integer from 1 to 262144. Maximum canonical JSON size accepted for one metadata object.
allowed_profiles no [] List of non-empty strings. Optional allow-list. When set, metadata must contain a profile value from this list.
default no null JSON object or null. Global metadata object used when the header is absent and no subject rule matches.
rules no [] Ordered list of subject rules. Subject-aware defaults. First matching rule wins when the header is absent.

Rule fields:

Field Required Default Valid values Description
subject yes none NATS subject pattern, for example mission.* or mission.>. Pattern matched against the message subject.
metadata yes none JSON object or null. Metadata default for matching subjects. null explicitly clears the global default.

Publisher Header Example

Publishers can provide mission metadata directly through the configured header:

nats pub mission.synthetic.sensor.track.0001 '{"event_id":"SYN-0001"}' \
  -H 'Nats-Sinks-Mission-Metadata: {"profile":"mission-event-v1","profile_version":1,"mission_id":"SYN-MISSION-001","f2t2ea_phase":"track","source_system":"synthetic-sensor"}'

Header values are authoritative. If the header is present and empty, the message receives no mission metadata even when defaults are configured. This allows publishers to explicitly say that no mission context applies.

Validation Rules

Mission metadata is treated as untrusted input:

  • the root value must be a JSON object,
  • duplicate JSON keys are rejected,
  • non-standard JSON constants such as NaN, Infinity, and -Infinity are rejected at the parser boundary,
  • object keys must start with a letter and contain only letters, numbers, underscores, dots, colons, or hyphens,
  • secret-looking key names such as password, token, secret, private_key, credential, or key_material are rejected,
  • strings, arrays, objects, nesting depth, integer range, and total serialized size are bounded,
  • control characters in keys and strings are rejected,
  • non-finite numbers are rejected,
  • configured allowed_profiles fail closed.
  • known first-party nats-sinks.*.v1 profiles receive additional bounded validation for required fields, hashes, URI schemes, timestamps, enum values, and numeric ranges.
  • operator-defined profile registry rules receive additional fail-closed validation for required fields, optional fields, JSON types, enum values, max string lengths, nested object limits, and unknown-field behavior.

Malformed mission metadata is a permanent validation failure. If a DLQ is configured, the runner publishes the message to the DLQ and ACKs the original only after DLQ publication succeeds. If DLQ publication fails, the original is not ACKed and remains eligible for redelivery.

sequenceDiagram
    participant JS as JetStream
    participant R as JetStreamSinkRunner
    participant DLQ as DLQ Subject

    JS->>R: Deliver message
    R->>R: Parse mission metadata header
    R->>R: Validation fails
    R->>DLQ: Publish failure record
    DLQ-->>R: Publish succeeds
    R->>JS: ACK original

Operator-Defined Profile Registry

Deployments can define their own mission metadata profiles in mission_metadata.profiles. A profile applies when the metadata object's profile field matches the configured profile name. If a version is configured, the metadata object must also contain a matching profile_version.

Profile registry validation runs after the generic hostile-JSON checks and after the optional allowed_profiles allow-list. Invalid profile data is a permanent validation failure. When DLQ is configured, the runner publishes a sanitized DLQ record before ACKing the original JetStream message.

Non-defence business event profile example:

{
  "mission_metadata": {
    "enabled": true,
    "allowed_profiles": ["business-event-v1"],
    "profiles": [
      {
        "name": "business-event-v1",
        "version": 1,
        "unknown_fields": "forbid",
        "required_fields": [
          {"name": "event_id", "type": "string", "max_length": 64},
          {
            "name": "event_type",
            "type": "string",
            "enum": ["created", "updated", "deleted"]
          }
        ],
        "optional_fields": [
          {"name": "source_system", "type": "string", "max_length": 128},
          {"name": "amount", "type": "number"},
          {"name": "attributes", "type": "object", "max_depth": 1}
        ]
      }
    ]
  }
}

Synthetic mission-support profile example:

{
  "mission_metadata": {
    "enabled": true,
    "allowed_profiles": ["normalized-link-event"],
    "profiles": [
      {
        "name": "normalized-link-event",
        "version": 1,
        "unknown_fields": "forbid",
        "required_fields": [
          {"name": "event_id", "type": "string", "max_length": 128},
          {"name": "source_gateway", "type": "string", "max_length": 128},
          {"name": "message_family", "type": "string", "enum": ["TADIL-J"]},
          {"name": "payload_sha256", "type": "string", "max_length": 64}
        ],
        "optional_fields": [
          {"name": "correlation_id", "type": "string", "max_length": 128},
          {"name": "classification", "type": "string", "max_length": 128},
          {"name": "data_quality", "type": "object", "max_depth": 2}
        ]
      },
      {
        "name": "fmv-custody-event",
        "version": 1,
        "unknown_fields": "forbid",
        "required_fields": [
          {"name": "event_id", "type": "string", "max_length": 128},
          {"name": "artifact_id", "type": "string", "max_length": 128},
          {"name": "artifact_sha256", "type": "string", "max_length": 64}
        ],
        "optional_fields": [
          {"name": "presentation_timestamp", "type": "string", "max_length": 64},
          {"name": "collection_id", "type": "string", "max_length": 128}
        ]
      }
    ]
  }
}

This registry is intentionally structural. It checks that configured metadata fields are present and bounded, but it does not parse tactical protocols, validate tactical semantics, authorize a release, or interpret domain-specific meaning. External gateways and adapters remain responsible for those decisions before publishing to JetStream.

First-Party Generic Profiles

Mission metadata can remain fully deployment-defined. When the profile value matches one of the first-party generic profiles below, the core applies stricter profile-specific validation while preserving the same optional, destination- neutral storage model.

Profile Purpose Required fields Typical use
nats-sinks.artifact-reference.v1 Stores a bounded reference to an external artifact instead of embedding large payloads. artifact_id, uri, media_type, sha256 Documents, images, video segments, model artifacts, synthetic review packages.
nats-sinks.data-quality.v1 Captures bounded data quality indicators. none beyond profile Commercial data pipelines, observability events, synthetic mission-support quality notes.
nats-sinks.geo-temporal-track-fix.v1 Captures custody for time-based track or movement updates without implementing a protocol. track_id, source_system, event_time Fleet telemetry, asset tracking, synthetic friendly-force tracking custody.
nats-sinks.object-relationship.v1 Captures object, relationship, version, and tombstone events. object_id, object_type, object_operation CMDB objects, supply-chain entities, digital twins, synthetic C2 object custody.

The profiles are generic by design. They do not implement Link 16, VMF, MIP4-IES, NFFI, FFTS, FMV, KLV, or any other domain protocol. External gateways, adapters, and normalizers remain responsible for authorization, sanitization, semantic validation, and domain-specific interpretation before publishing an event to JetStream.

Artifact reference example:

{
  "profile": "nats-sinks.artifact-reference.v1",
  "artifact_id": "doc-1001",
  "uri": "s3://example-bucket/documents/doc-1001.json",
  "media_type": "application/json",
  "size_bytes": 2048,
  "sha256": "0000000000000000000000000000000000000000000000000000000000000000",
  "created_at": "2026-05-31T10:15:00Z",
  "source": "document-pipeline",
  "relationship": "payload-reference",
  "retention_category": "audit",
  "classification": "internal",
  "labels": ["document", "audit"]
}

Data quality example:

{
  "profile": "nats-sinks.data-quality.v1",
  "accuracy": 0.98,
  "completeness": 1.0,
  "consistency": 0.99,
  "timeliness": 0.94,
  "validity": 1.0,
  "confidence": 0.97,
  "quality_source": "synthetic-quality-gate",
  "assessed_at": "2026-05-31T10:17:00Z"
}

Track/fix example:

{
  "profile": "nats-sinks.geo-temporal-track-fix.v1",
  "track_id": "asset-1001",
  "source_system": "fleet-tracker",
  "event_time": "2026-05-31T10:18:00Z",
  "receive_time": "2026-05-31T10:18:02Z",
  "position_kind": "coordinates",
  "position_reference": {
    "latitude": 52.0,
    "longitude": 5.0
  },
  "position_quality": "gnss",
  "speed": 12.5,
  "heading": 180.0,
  "precision_category": "full",
  "redaction_level": "none",
  "confidence": 0.91,
  "synthetic": true
}

Object/relationship example:

{
  "profile": "nats-sinks.object-relationship.v1",
  "object_id": "server-1001",
  "object_type": "configuration_item",
  "object_version": "7",
  "object_operation": "upsert",
  "source_system": "cmdb",
  "schema_profile": "cmdb-object",
  "schema_version": "1",
  "event_time": "2026-05-31T10:20:00Z",
  "data_quality": {
    "confidence": 0.9,
    "quality_source": "cmdb-sync"
  }
}

Runnable JSON fixtures live under the repository examples/metadata-profiles/ directory.

Oracle Storage

Oracle stores mission metadata in the MISSION_METADATA_JSON column by default. The column name is configurable through sink.columns.mission_metadata.

Recommended column:

mission_metadata_json json

Example row value:

{
  "profile": "mission-event-v1",
  "profile_version": 1,
  "mission_id": "SYN-MISSION-001",
  "operation_id": "SYN-OP-ALPHA",
  "f2t2ea_phase": "track",
  "source_system": "synthetic-sensor",
  "source_confidence": 0.91,
  "releasability": ["NATO", "mission-partner"]
}

The generic METADATA_JSON document also includes the same object under its mission_metadata field so operators can inspect one complete framework metadata snapshot.

File Sink Output

The file sink writes mission metadata as a top-level field in each output record:

{
  "schema": "nats_sinks.file.message.v1",
  "subject": "mission.synthetic.sensor.track.0001",
  "priority": "immediate",
  "classification": "NATO SECRET",
  "labels": "synthetic;mission-test;f2t2ea-example",
  "labels_list": ["synthetic", "mission-test", "f2t2ea-example"],
  "mission_metadata": {
    "profile": "mission-event-v1",
    "profile_version": 1,
    "mission_id": "SYN-MISSION-001",
    "f2t2ea_phase": "track"
  },
  "payload": {
    "event_id": "SYN-0001"
  }
}

When mission metadata is absent, the file sink writes JSON null in the top-level mission_metadata field and under metadata.mission_metadata.

Relationship To Priority, Classification, And Labels

Mission metadata does not replace priority, classification, or labels. Those fields remain small, stable, framework-wide fields with dedicated storage in Oracle and file sink output. Mission metadata is for richer context that may vary between deployments or use-case families.

Recommended split:

Need Use
Routing urgency, queue attention, operator priority message_metadata.priority
Information marking such as NATO SECRET or internal message_metadata.classification
Small searchable tags message_metadata.labels
Mission, operation, platform, sensor, track, confidence, releasability, or phase context mission_metadata

Defence Use Cases

The defence examples in this repository use mission metadata for synthetic, metadata-only lifecycle tagging. See F2T2EA Event Phase Tagging for a detailed blueprint.

The feature is not a targeting system, fire-control system, weapons-release mechanism, rules-of-engagement engine, or autonomous decision layer. It is a data custody mechanism for preserving event context with clear validation, storage, and redelivery semantics.