Skip to content

JSON-cppagent-mqtt: Header.testIndicator absent on MQTT Streams Header #131

@ottobolyos

Description

@ottobolyos

Summary

Under the JSON-CPPAGENT-MQTT document format, the MTConnectStreams.Header object omits testIndicator entirely, while cppagent's JSON v2 printer emits testIndicator: false (the XSD-optional attribute's default-false value) on every Header. The XSD marks testIndicator as optional, so the absence is not an XSD violation — but the JSON-CPPAGENT-MQTT format label promises cppagent-JSON-v2 compatibility, and cppagent consistently emits the field.

Environment

  • MTConnect.NET-Applications-Agents + MTConnect.NET-JSON-cppagent at v6.9.0 (official Docker image trakhound/mtconnect.net-agent:6.9.0, published 2025-10-16 — binary-equivalent to v6.9.0.2).
  • Broker: eclipse-mosquitto:2.0.22.
  • Comparison agent: mtconnect/agent:latest = cppagent v2.7.0.7 with JsonVersion = 2.
  • Format ID: JSON-CPPAGENT-MQTT.

Reproduction

Minimum rig — mqtt-relay module pointed at local Mosquitto:

modules:
- mqtt-relay:
    server: localhost
    port: 1883
    documentFormat: JSON-CPPAGENT-MQTT
    topicPrefix: MTConnect/Document
    topicStructure: Document

Run the agent, capture a Current payload, and inspect the Header:

mosquitto_sub -h localhost -t 'MTConnect/Document/Current/<uuid>' -C 1 \
  | jq '.MTConnectStreams.Header'

Observed — MT.NET

{
  "instanceId": 1776717208,
  "version": "6.9.0.0",
  "sender": "9e17047e9163",
  "bufferSize": 150000,
  "firstSequence": 1,
  "lastSequence": 36,
  "nextSequence": 37,
  "deviceModelChangeTime": "2026-04-20T20:33:28.8491672Z",
  "creationTime": "2026-04-20T20:33:39.9655145Z"
}

No testIndicator property.

Expected — cppagent JSON v2 reference

Run mtconnect/agent:latest with JsonVersion = 2 and the same MqttService sink, capture the same topic:

{
  "version": "2.7.0.7",
  "creationTime": "2026-04-20T19:28:33Z",
  "testIndicator": false,
  "instanceId": 1776713243,
  "sender": "localhost",
  "schemaVersion": "2.7",
  "deviceModelChangeTime": "",
  "bufferSize": 131072,
  "nextSequence": 104,
  "lastSequence": 103,
  "firstSequence": 1
}

cppagent emits testIndicator: false even when the agent is not in test mode — the field is always present so consumers don't need hasOwnProperty checks.

Evidence files: current.json + cppagent-current.json.

Authority

  • XSD: MTConnectStreams_2.7.xsd (and every v2.x back to v1.3) declares testIndicator on HeaderAttributesType with use="optional":

    <xs:attribute name='testIndicator' type='xs:NMTOKEN' use='optional'/>

    XSD optionality means an emitter is not required to write the attribute. It does not forbid writing it with a default value.

  • cppagent JSON v2 reference: the printer source and test_package/json_printer_stream_test.cpp both show testIndicator always emitted. The JSON-CPPAGENT-MQTT format label is an explicit compatibility promise with this output; consumers that select the format ID are entitled to expect the field present.

  • XMI: testIndicator is defined on HeaderAttributesType (and on every concrete Header complex type) in MTConnectSysMLModel.xml. It has no normative multiplicity > 0, confirming optionality.

Root cause — library source

libraries/MTConnect.NET-JSON-cppagent/Streams/JsonStreamsHeader.cs does declare TestIndicator with [JsonPropertyName("testIndicator")]:

[JsonPropertyName("testIndicator")]
public bool TestIndicator { get; set; }

…and it is populated from the source header. But the System.Text.Json serialiser options in use apparently skip default-value booleans (false is the zero-value for bool), so testIndicator never reaches the wire. Candidates to verify:

  • JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault somewhere in the formatter pipeline.
  • Or the property is written via a custom converter that skips defaults.

Impact

  • Low on its own. testIndicator is XSD-optional and consumers that tolerate its absence work fine.
  • Tightens the JSON-CPPAGENT-MQTT format-label contract: the cppagent reference always emits this field, so strict cppagent-compat consumers may expect it present.
  • Slightly raises the bar for cross-implementation test fixtures — diff-based integration tests between MT.NET and cppagent payloads need to whitelist this difference.

Suggested fix

  1. Ensure testIndicator serialises unconditionally — either by changing the serialiser's ignore-condition for this property to Never, or by wrapping the property in a nullable form and always assigning false explicitly. Match cppagent's "always emit" behaviour.
  2. Same treatment for JsonDevicesHeader.TestIndicator and JsonAssetsHeader.TestIndicator if they exist.
  3. Add a unit test that round-trips a Header with TestIndicator = false and asserts the serialised JSON contains "testIndicator": false.

Stability across MTConnect versions

testIndicator has been optional on HeaderAttributesType since v1.3+ with no semantic change. cppagent's "always emit" behaviour has been stable across its JSON v2 lineage. Fix is version-agnostic.

Related issues

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions