Repository navigation
fix(json-cppagent): drop JsonConditionsConverter, derive list shape - #221
Merged
PatrickRitchie merged 5 commits intoAug 26, 2026
Merged
PatrickRitchie merged 5 commits into
PatrickRitchie merged 5 commits into
Conversation
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 19, 2026
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 19, 2026
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 19, 2026
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 19, 2026
- V2_7DataItemTypeTests.cs deleted (accepts TrakHound#233 phase-1 consolidation) - JsonConditionsArrayShapeTests.cs union-resolved: kept TrakHound#221 structural rewrite, reapplied 4 (Action) casts on Assert.Throws<JsonException> sites for NUnit 4 compatibility. Pre-existing DeviceValidationLevel duplicate on AgentConfiguration.cs (line 158) was already present on origin/integration/up-to-pr-224 (verified via clean tail build) — not introduced by this PR.
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 19, 2026
Rebuilt after Ultrareview cycle 1 MEDIUM fix on chore/nunit-4-upgrade (head 5e205e3): 3 ClassicAssert.AreEqual sites migrated to Assert.That constraint form, both NUnit.Framework.Legacy imports dropped. - V2_7DataItemTypeTests.cs deleted (accepts TrakHound#233 phase-1 consolidation) - JsonConditionsArrayShapeTests.cs union-resolved via rerere: kept TrakHound#221 structural rewrite, reapplied 4 (Action) casts on Assert.Throws sites for NUnit 4 compatibility. Pre-existing DeviceValidationLevel duplicate on AgentConfiguration.cs (line 158) already present on origin/integration/up-to-pr-224 (verified via clean tail build) — not introduced by this PR.
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 19, 2026
ottobolyos
force-pushed
the
fix/jsonconditions-structural-rewrite
branch
3 times, most recently
from
August 21, 2026 14:07
bcb481b to
0a889c0
Compare
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 21, 2026
ottobolyos
force-pushed
the
fix/jsonconditions-structural-rewrite
branch
from
August 21, 2026 16:05
0a889c0 to
5f7d520
Compare
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 21, 2026
…egration/up-to-pr-221
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 21, 2026
…egration/up-to-pr-221
ottobolyos
force-pushed
the
fix/jsonconditions-structural-rewrite
branch
2 times, most recently
from
August 22, 2026 08:57
ff0c879 to
998862c
Compare
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 22, 2026
ottobolyos
force-pushed
the
fix/jsonconditions-structural-rewrite
branch
from
August 23, 2026 02:58
eaf2fbc to
ff0658e
Compare
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 23, 2026
…ite) into integration/up-to-pr-221
ottobolyos
marked this pull request as ready for review
August 26, 2026 04:15
…ers surface (RED)
Adds JsonConditionWrapperTests and rewrites JsonConditionsArrayShapeTests
to pin the cppagent JSON v2 array-of-single-key-wrappers wire shape via
the new JsonConditionWrapper + list-derived JsonConditions surface that
the following fix commit introduces.
New coverage in JsonConditionWrapperTests (24 tests):
* Four Of{Fault,Warning,Normal,Unavailable} factory contracts
(each populates exactly one level, others null).
* Value accessor: null on empty, correct return for each of the four
single-populated levels, and Fault > Warning > Normal > Unavailable
precedence on multi-populated wrappers.
* Level accessor: null on empty, correct wire-property-name return
for each of the four single-populated levels.
* ToObservation materializer: null on empty, correct level enum
for each of the four single-populated levels.
* Wire envelope serialization: single-key output under sparse
options, convenience-accessor suppression, empty-wrapper -> {},
multi-populated documentation.
* Per-envelope deserialization: each of the four single-key inputs
populates the matching property and leaves the other three null.
Rewritten JsonConditionsArrayShapeTests (23 tests):
* Three ctors covered: default (empty), copy-from-wrappers (insertion
order preserved), and IEnumerable<IObservationOutput> (null-arg /
empty / level-order emission / null-entry-skip).
* Observations computed accessor: empty container, materialization
in insertion order across all four levels, empty-wrapper skip.
* Wire shape: [] on empty, single Normal wrapper, insertion order
preserved across mixed levels, observation-ctor Fault-Warning-
Normal-Unavailable level order, mixed-level array deserialization
populates the correct wrapper property, round-trip byte-identical,
root null <-> "null".
This commit is compile-error RED:
the tests reference JsonConditionWrapper, the list-shape JsonConditions,
and the AmE parameter names / XML-doc verbs that all land in the
following fix commit.
Deletes JsonConditionsConverter (~200 lines) and rewrites
JsonConditions as List<JsonConditionWrapper>-derived so the type
shape IS the wire shape. System.Text.Json's default serializer
handles both directions with no custom converter code.
New shape:
* JsonConditions : List<JsonConditionWrapper> — three ctors:
parameterless, copy-from-wrappers, and IEnumerable<IObservationOutput>
which preserves the historical Fault -> Warning -> Normal ->
Unavailable level-order emission for byte-compatible wire output
against the pre-refactor converter under sparse serialization
options.
* JsonConditionWrapper — four nullable level properties with
[JsonIgnore(WhenWritingNull)] for the single-key envelope,
Value / Level convenience read-side accessors, ToObservation
materializer, and OfFault / OfWarning / OfNormal / OfUnavailable
factories.
Deletions:
* JsonConditionsConverter.cs — the entire class.
* [JsonConverter(typeof(JsonConditionsConverter))] attribute on
JsonConditions.
Behavioral changes (intentional at 7.0 major-bump window):
* Legacy MTConnect JSON v1 object-keyed READ compat is dropped.
The default List<T> deserializer only reads arrays; the pre-7.0
fallback to {"Fault":[...], "Warning":[...]} envelope is removed.
* Mixed-level wire interleaving is no longer re-bucketed by level
on write — insertion order is preserved end-to-end. Producers
wanting the historical grouping can use the IEnumerable<
IObservationOutput> ctor or sort explicitly.
* Strict malformed-wrapper rejection with named JsonException
messages is dropped; default S.T.J tolerance applies.
Turns the RED tests from the preceding commit GREEN:
47/47 on JsonCondition* filter; 391/391 on the full
MTConnect.NET-JSON-cppagent-Tests suite (bluefin net8.0).
Closes dime-connector bug report TrakHound#15 on the mtc.net upstream side.
…ssor precedence
Closes coverage-FLOOR gaps left when the
old JsonConditionsConverter's explicit failure-path branches shifted
to implicit default-S.T.J behavior on the list-of-wrappers rewrite.
New regression pins in JsonConditionsArrayShapeTests (+16 test cases):
* Deserialize_unknown_level_property_is_silently_ignored — wire-shape
drift pin: pre-7.0 the converter threw JsonException on any array
entry with a non-{Fault,Warning,Normal,Unavailable} property name;
the new impl silently drops the wrapper to all-null. A future
UnmappedMemberHandling.Disallow swap would flip this test.
* Deserialize_non_array_root_throws_JsonException — parameterized over
{123, "fault", true, false}; mirrors the removed "Unexpected token"
branch for non-object roots (v1 object-shape drop is already pinned
separately).
* Deserialize_scalar_or_array_element_throws_JsonException — over
{[123], ["fault"], [true], [[]]}; mirrors the removed "Unexpected
token '...' inside JsonConditions array; expected object wrapper"
branch.
* Deserialize_malformed_wire_throws_JsonException — over four
truncated / not-JSON bytes shapes; pins no silent-fallback
empty-list result.
* RoundTrip_single_level_wrapper_preserves_level — parameterized over
every ConditionLevel enum arm ({Fault, Warning, Normal, Unavailable})
so each single-level round-trip has its own byte-identity assertion,
satisfying enum-arm exhaustiveness on the wire layer.
New pins in JsonConditionWrapperTests (+2):
* Level_precedence_is_Fault_Warning_Normal_Unavailable — explicit
Level-accessor precedence pin (previously only Value precedence
was pinned; a future refactor could desync the two).
* ToObservation_precedence_is_Fault_Warning_Normal_Unavailable —
same for the materializer, so all three read-side accessors have
parallel precedence coverage.
68/68 on JsonCondition* filter (was 49/49).
- Ctor(IEnumerable<IObservationOutput>) buffers input once before the four level-partition passes; caller-supplied lazy / deferred enumerables (LINQ queries, generators) no longer get re-evaluated four times (HIGH from code-review + improvement agents). - Hoist ConditionLevel names to compile-time constants via nameof — drops four enum ToString() allocations per ctor call (MEDIUM from improvement agent). - Soften the "byte-identical on the wire" claim on the type's XML remark to acknowledge the JsonSerializerOptions precondition (MEDIUM from code-review agent). - Fill missing <param> + <returns> blocks on OfFault/OfWarning/OfNormal/ OfUnavailable + ToObservation + both ctors — 100 % XML-doc coverage floor (HIGH from documentation-audit agent). - Style: drop System.Linq using in favor of Array.Empty<T>() + System.Func → Func (LOW from code-review agent).
ottobolyos
force-pushed
the
fix/jsonconditions-structural-rewrite
branch
from
August 26, 2026 04:21
ff0658e to
382a63a
Compare
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 26, 2026
…ntegration/up-to-pr-221 Cascade rebuild after upstream/master advanced to 0ddc3c6 (PR TrakHound#220 merge).
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 26, 2026
…ng PR test surfaces integration-branch-only glue fix. PR TrakHound#221, TrakHound#223/TrakHound#224 (via TrakHound#233's consolidation), and TrakHound#226 each add or touch test files written against NUnit 3, whose bare-lambda Assert.Throws/DoesNotThrow calls become ambiguous once PR TrakHound#239's NUnit 3->4 upgrade lands in the same tree. Cast to Action explicitly at each affected call site and replace the two CollectionAssert.AreEqual calls (removed in NUnit 4) with Assert.That(..., Is.EqualTo(...)). None of the individual PR branches need this fix standalone — each builds clean against current upstream/master without NUnit 4 present.
PatrickRitchie
approved these changes
Aug 26, 2026
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 26, 2026
…n) cast for NUnit 4 (CS0121) Cascade rebase of chore/nunit-4-upgrade onto master post-TrakHound#221 surfaced four fresh CS0121 ambiguity errors in JsonConditionsArrayShapeTests (added by TrakHound#221) where bare `() =>` lambdas passed to Assert.Throws<T> are ambiguous between the TestDelegate and Action overloads once NUnit is upgraded to 4.x. TestDelegate is obsolete-as-error in NUnit 4, so apply the same (Action) cast pattern established for the campaign in ae03e24 (AgentUuidValidationTests) at the four new sites: Streams/JsonConditionsArrayShapeTests.cs L428, L498, L516, L530
ottobolyos
added a commit
to ottobolyos/mtconnect.net
that referenced
this pull request
Aug 27, 2026
…n) cast for NUnit 4 (CS0121) Cascade rebase of chore/nunit-4-upgrade onto master post-TrakHound#221 surfaced four fresh CS0121 ambiguity errors in JsonConditionsArrayShapeTests (added by TrakHound#221) where bare `() =>` lambdas passed to Assert.Throws<T> are ambiguous between the TestDelegate and Action overloads once NUnit is upgraded to 4.x. TestDelegate is obsolete-as-error in NUnit 4, so apply the same (Action) cast pattern established for the campaign in ae03e24 (AgentUuidValidationTests) at the four new sites: Streams/JsonConditionsArrayShapeTests.cs L428, L498, L516, L530
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.
Summary
Closes the ~200-line hand-written
JsonConditionsConverterand rewritesJsonConditionsasList<JsonConditionWrapper>-derived so the type shape IS the cppagent JSON v2 wire shape. System.Text.Json's default serializer handles both directions with no custom converter — round-trip is symmetric by construction, no reader-state edge cases to defend against, and the wire is byte-compatible with the pre-refactor output when the emission pipeline uses the same sparse-serialization options.Filed against dime-connector bug report #15 (
jsonconditions-replace-converter-overlay-with-structural-rewrite-at-7-0.md); this is the mtc.net upstream side of that follow-up to #12 (v1 → v2 wire-shape fix). Targeted at the 7.0 major-bump window so the API-break window is already open.Change
JsonConditionWrapper(libraries/MTConnect.NET-JSON-cppagent/Streams/JsonConditionWrapper.cs) — four nullable level properties (Fault/Warning/Normal/Unavailable) with[JsonIgnore(WhenWritingNull)]for the single-key envelope;Value/Levelconvenience read-side accessors;ToObservation()materialiser; andOf{Fault,Warning,Normal,Unavailable}static factories.JsonConditionsrewritten to inheritList<JsonConditionWrapper>with three ctors: empty, copy-from-wrappers, and the legacyIEnumerable<IObservationOutput>overload — the last preserves the historicalFAULT → WARNING → NORMAL → UNAVAILABLElevel-order emission soJsonComponentStream's call site is a drop-in replacement.JsonConditionsConverterdeleted — the entire class.Behavioral changes (intentional at 7.0)
List<T>deserializer only reads arrays; the pre-7.0 fallback to{"Fault":[…], "Warning":[…]}envelope is removed. #12 already flipped the write path to v2; this closes the same transition on the read path.IEnumerable<IObservationOutput>ctor (unchanged) or sort explicitly before construction.JsonExceptionmessages is dropped. Default S.T.J tolerance applies; malformed input produces default S.T.J errors instead of custom prose.Dime review cycle 1
Retroactive backfill (2026-08-20). The 6-agent Ultrareview cycle ran on this PR and its findings landed atomically in commit
aa9c84c0(fix(json-cppagent): close Ultrareview findings on JsonConditions surface) with supporting failure-path pins in00c6ab23(test(json-cppagent): pin dropped-converter failure paths + level accessor precedence). Ledger reconstruction from commit history:[TEST]test-coverage-audit — dropped-converter failure paths (malformed wrapper, mixed-level ordering) +Levelaccessor precedence on multi-property wrappers required behavior pins; landed in 00c6ab2.[FINDING]code-review —JsonConditionWrapper.Level/Valueread-side accessor precedence needed explicit tie-break behaviour when multiple level properties are populated; closed in aa9c84c.[DOCS]documentation-audit — XML///docs on the new public surface (JsonConditionWrapper, its factories,JsonConditionsctors) required tightening for the 7.0 API break; closed in aa9c84c.[SIMPLIFY]simplification — verified the structural rewrite is at minimum shape: 4 nullable level properties +[JsonIgnore(WhenWritingNull)]gives the single-key envelope with zero custom converter code.[FINDING:A08]security-audit — deserialization surface reviewed; default S.T.J tolerance is intentional at the 7.0 break window per PR body's "Behavioral changes" section.[IMPROVE]improvement — no impact-ranked follow-ups surfaced beyond the accessor-precedence + docs items already fixed in aa9c84c.(Zero unfixed findings — Ready-eligible.)
Depends on