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
- 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.
- Same treatment for
JsonDevicesHeader.TestIndicator and JsonAssetsHeader.TestIndicator if they exist.
- 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
Summary
Under the
JSON-CPPAGENT-MQTTdocument format, theMTConnectStreams.Headerobject omitstestIndicatorentirely, while cppagent's JSON v2 printer emitstestIndicator: false(the XSD-optional attribute's default-false value) on every Header. The XSD markstestIndicatoras optional, so the absence is not an XSD violation — but theJSON-CPPAGENT-MQTTformat label promises cppagent-JSON-v2 compatibility, and cppagent consistently emits the field.Environment
MTConnect.NET-Applications-Agents+MTConnect.NET-JSON-cppagentat v6.9.0 (official Docker imagetrakhound/mtconnect.net-agent:6.9.0, published 2025-10-16 — binary-equivalent to v6.9.0.2).eclipse-mosquitto:2.0.22.mtconnect/agent:latest= cppagent v2.7.0.7 withJsonVersion = 2.JSON-CPPAGENT-MQTT.Reproduction
Minimum rig —
mqtt-relaymodule pointed at local Mosquitto:Run the agent, capture a Current payload, and inspect the 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
testIndicatorproperty.Expected — cppagent JSON v2 reference
Run
mtconnect/agent:latestwithJsonVersion = 2and 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: falseeven when the agent is not in test mode — the field is always present so consumers don't needhasOwnPropertychecks.Evidence files:
current.json+cppagent-current.json.Authority
XSD:
MTConnectStreams_2.7.xsd(and every v2.x back to v1.3) declarestestIndicatoronHeaderAttributesTypewithuse="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.cppboth showtestIndicatoralways emitted. TheJSON-CPPAGENT-MQTTformat label is an explicit compatibility promise with this output; consumers that select the format ID are entitled to expect the field present.XMI:
testIndicatoris defined onHeaderAttributesType(and on every concrete Header complex type) inMTConnectSysMLModel.xml. It has no normative multiplicity > 0, confirming optionality.Root cause — library source
libraries/MTConnect.NET-JSON-cppagent/Streams/JsonStreamsHeader.csdoes declareTestIndicatorwith[JsonPropertyName("testIndicator")]:…and it is populated from the source header. But the
System.Text.Jsonserialiser options in use apparently skip default-value booleans (falseis the zero-value forbool), sotestIndicatornever reaches the wire. Candidates to verify:JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefaultsomewhere in the formatter pipeline.Impact
testIndicatoris XSD-optional and consumers that tolerate its absence work fine.JSON-CPPAGENT-MQTTformat-label contract: the cppagent reference always emits this field, so strict cppagent-compat consumers may expect it present.Suggested fix
testIndicatorserialises unconditionally — either by changing the serialiser's ignore-condition for this property toNever, or by wrapping the property in a nullable form and always assigningfalseexplicitly. Match cppagent's "always emit" behaviour.JsonDevicesHeader.TestIndicatorandJsonAssetsHeader.TestIndicatorif they exist.TestIndicator = falseand asserts the serialised JSON contains"testIndicator": false.Stability across MTConnect versions
testIndicatorhas been optional onHeaderAttributesTypesince 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
JSON-cppagent-mqtt:Header.schemaVersionabsent on MQTT Streams Header #130 —Header.schemaVersionabsent — another missing Header attribute from the same class.Header.versionreports library assembly version instead of MTConnect release #127 —Header.versionreports library assembly version — adjacent Header defect.MTConnectStreams.schemaVersion/MTConnectDevices.schemaVersionhardcoded to"2.0"inJSON-cppagent-mqttformatter #128 —MTConnectStreams.schemaVersion/MTConnectDevices.schemaVersionhardcoded to"2.0"— parallel Header-semantic bug; the JSON-cppagent-mqtt formatter owns all three.References
libraries/MTConnect.NET-JSON-cppagent/Streams/JsonStreamsHeader.cstest_package/json_printer_stream_test.cppMTConnectStreams_2.7.xsd—HeaderAttributesType.testIndicatordeclareduse="optional".current.json+cppagent-current.json.