Repository navigation
[#603] Adopt OPC UA quality codes - #628
Merged
Merged
Conversation
ibinshtok
approved these changes
Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[#603] Adopt OPC UA quality codes
Closes #603. Per the spec team decision that this goes into v4.
The three defined qualities —
0BAD,192GOOD,500STALE — are OPC DA legacy (192is theOPC DA Good byte), with no Uncertain tier and no machine-readable reason for a bad value. The only
assertion on the field,
payloads-quality-value, required the value to be an int32, which the schemaalready enforces.
Why now, and why this is a free change
qualitywas promoted to a first-class Metric field ind9a338d([#145]), so the carrier question isalready settled and #603 is purely about vocabulary. Nothing implements that field yet: Tahu's
sparkplug_b.protohas no quality field at all, and v3 quality actually travels as a PropertySetproperty named
"Quality"(SparkplugUtil.getQualityCode(), defaulting to 192). So the vocabulary isa free choice right now and stops being free when v4 ships.
Design
Adopts the OPC UA StatusCode numbering — normatively the bit layout and severity encoding,
informatively the wider code list. Ignition 8 already uses an OPC-UA-shaped
QualityCodeinternally,so this moves the wire format toward where the dominant Sparkplug source already is.
New
Qualitysection, six statements:quality-severity-valid— bits 30–31 ∈ {00Good,01Uncertain,10Bad};11reservedquality-severity-authoritative— consumers act on severity alone, MUST NOT require subcode recognitionquality-absent-good— absent ≡ Goodquality-recognized-codes— guaranteed named set; producers MAY use any OPC UA codequality-stale-code— STALE ≡UncertainLastUsableValue(0x40900000)quality-context-not-required— diagnostic text onlyquality-severity-authoritativeis what lets the spec name eleven codes rather than enumerate ~250:an unrecognized subcode still yields correct Good/Uncertain/Bad handling. All eleven values were
checked against the OPC Foundation's published
StatusCode.csv.The 12 Chapter 5 STALE statements are unchanged — they say "mark as STALE", and STALE now resolves to
a code.
int32→uint32OPC UA StatusCode is a UInt32 and Bad severity is bit 31, so every Bad code is negative in an
int32 (
BadNotConnected=0x808A0000= −2138439680). Three consequences:int32to 64 bits before varint encoding: 10 bytes on the wireversus 5 for the same bits as
uint32.qualitywas the onlyint32in the schema;uint32is already used elsewhere.Caveat: protobuf-java maps
uint32toint, so Tahu still needsInteger.toUnsignedLong()forcomparison and display. C#, Go, C++, Python and JavaScript get a genuinely unsigned type.
TCK
SendComplexDataTest.checkQualityCodeRequirement()validated the v3 property mechanism — key"Quality", values 0/192/500 — which v4 no longer defines. Removed with a comment rather thanretargeted, since there is nothing equivalent to check; it becomes coverage for the v4 TCK rewrite.
Note for reviewers
The bare
[tck-not-testable]form is unsafe.tck-audit.xsl:269falls back to a position-derivedletter when the role carries no
id-, so untestable statements get ids likea/b/cthat are notunique across the document, and
requirements.pyflattens them into one Java class — this broketck:compileJavawith duplicateID_A/ID_Buntil each statement was given an explicit id. The XSLaccepts
[tck-not-testable tck-id-…], which is what this PR uses.Follow-up: the two
[tck-not-testable]statements added in #601 hold lettersbandeby luck,alongside the pre-existing Chapter 5 one at
i. They compile today but will collide with any futureuntestable statement, and should be given explicit ids.
Verified:
./gradlew buildsucceeds from clean; 605 → 610 assertions; zero dangling TCK constants;all
link:#anchors resolve; every tck-id appears exactly twice.