Skip to content

fix(agent): reject non-UUID AgentUuid on override + persisted paths - #220

Merged
PatrickRitchie merged 7 commits into
TrakHound:masterfrom
ottobolyos:fix/agent-uuid-lifecycle-hardening
Aug 26, 2026
Merged

fix(agent): reject non-UUID AgentUuid on override + persisted paths#220
PatrickRitchie merged 7 commits into
TrakHound:masterfrom
ottobolyos:fix/agent-uuid-lifecycle-hardening

Conversation

@ottobolyos

@ottobolyos ottobolyos commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Hardens the Agent meta-device UUID resolution slice added by #168 so malformed input never reaches the wire — closing the gap on both the operator-supplied override AND the persisted agent.information.json paths. The prior single-path validation left Path 2 open: a corrupted state file (or a pre-hardening agent version that wrote non-UUID content) would flow straight to the wire and fail every downstream MTConnect Part 1 XSD-validating consumer on typed enum/decimal DataItems.

Standard interpretation — XMI vs XSD ambiguity

The MTConnect standard is not internally consistent on whether the uuid attribute must be a strict RFC 4122 / ISO 11578 UUID or an arbitrary non-empty string. This PR adopts the XMI/SysML interpretation. Both source-of-truth citations:

XMI/SysML glossary (strict-UUID reading)build/sysml-model/MTConnectSysMLModel.xml, glossary enumeration literal UUID (xmi:id='_19_0_3_68e0225_1605548124036_660108_342'):

universally unique identifier as specified in ISO 11578 or RFC 4122.

XSD (permissive-string reading)tests/Compliance/MTConnect-Compliance-Tests/Schemas/v2_7/MTConnectDevices_2.7.xsd, simpleType UuidType:

<xs:simpleType name='UuidType'>
  <xs:annotation>
    <xs:documentation>
      A universally unique id that uniquely identifies the element for
      it's entire life
    </xs:documentation>
  </xs:annotation>
  <xs:restriction base='xs:string'/>
</xs:simpleType>

xs:string with no pattern facet — schema-valid for any non-empty string. The field-level documentation on Device.uuid in the same XSD reinforces the permissive reading:

The components universally unique id. This can be composed of the manufactures id or name and the serial number.

Rationale for choosing XMI-strict: the XMI glossary is the normative source in the MTConnect-Standard sysml-first pipeline (XSDs are generated from the SysML model, not the other way around), and RFC 4122 canonical UUIDs are a superset of every reasonable operator-authored identifier scheme — an operator whose in-house scheme is <manufacturer>-<serial> can trivially derive a stable UUID v5 from it, but a downstream consumer parsing a bare string can't tell whether it's meant to be a UUID or something else. Rejecting non-UUID on the wire preserves the safer contract for consumers.

Open question for the maintainer: if the XSD-permissive reading is deliberate (i.e. the standard truly means "any string that's unique enough for your deployment"), this PR is over-strict and the fix should instead be a validation warning + pass-through, not a rejection. Please confirm intent before merge.

Change

  • New AgentUuidResolver.Resolve (public static, MTConnect.NET-Common) implements the three-path algorithm:
    • Path 1 — validated operator override wins;
    • Path 2 — validated persisted state wins over derivation;
    • Path 3 — deterministic UUID v5 derivation from ServiceName.
      Malformed input on Path 1 OR Path 2 logs a warning via a delegate hook (so MTConnect.NET-Common takes no hard dependency on NLog) and falls through to the next path. Raw values echoed to the warn log are pre-sanitized (CRLF stripped, truncated to 64 chars) as guards against log-injection and paste-in-wrong-field secret leakage.
  • MTConnectAgentApplication.RunAgent routes through the shared resolver instead of hand-rolling the dual-if resolution. Collapses the two-branch shape that re-tested string.IsNullOrEmpty twice.
  • DeterministicAgentUuid.TryValidate parameter renamed normalisednormalized (American English spelling is used throughout committed code); XML-doc verbs updated to match. Positional / out var callers unaffected.
  • Test fixtures brought forwardAgentUuidConfigOverrideTests + AgentUuidLongitudinalInvariantsTests now route their boot simulation through AgentUuidResolver.Resolve instead of inline replay, and their fixture literals are canonical RFC 4122 UUIDs (previously non-UUID strings that survived only because the inline replay omitted TryValidate — fake-green). Every fixture marked [NonParallelizable] with orphan-.bak.* sweep.

Depends on

@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from aaeaa8e to 8fd6d38 Compare August 19, 2026 12:12
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterisation tests per CONVENTIONS
§1.0d-trigies-novodecies — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behaviour, so they land GREEN; RED-first ordering
(§1.0d-trigies-octies) does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalised to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterisation.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per CONVENTIONS
  §1.0d-decies (AmE spelling universal in MTConnect.NET canonical
  surfaces).

Adds tests pinning the new behaviour:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
# Conflicts:
#	agent/MTConnect.NET-Applications-Agents/MTConnectAgentApplication.cs
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from 6dc88d6 to 187f069 Compare August 19, 2026 22:05
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterisation tests per CONVENTIONS
§1.0d-trigies-novodecies — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behaviour, so they land GREEN; RED-first ordering
(§1.0d-trigies-octies) does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalised to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterisation.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per CONVENTIONS
  §1.0d-decies (AmE spelling universal in MTConnect.NET canonical
  surfaces).

Adds tests pinning the new behaviour:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 19, 2026
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from 187f069 to e2d3705 Compare August 21, 2026 06:18
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterisation tests per CONVENTIONS
§1.0d-trigies-novodecies — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behaviour, so they land GREEN; RED-first ordering
(§1.0d-trigies-octies) does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalised to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterisation.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per CONVENTIONS
  §1.0d-decies (AmE spelling universal in MTConnect.NET canonical
  surfaces).

Adds tests pinning the new behaviour:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from e2d3705 to 5ac7afb Compare August 21, 2026 06:21
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterisation tests per CONVENTIONS
§1.0d-trigies-novodecies — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behaviour, so they land GREEN; RED-first ordering
(§1.0d-trigies-octies) does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalised to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterisation.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per CONVENTIONS
  §1.0d-decies (AmE spelling universal in MTConnect.NET canonical
  surfaces).

Adds tests pinning the new behaviour:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from 5ac7afb to 4bac41b Compare August 21, 2026 08:33
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterization tests — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behavior, so they land GREEN; RED-first ordering does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalized to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterization.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per project convention (AmE spelling is universal in MTConnect.NET canonical surfaces).

Adds tests pinning the new behavior:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from 4bac41b to 153a487 Compare August 21, 2026 14:07
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterization tests — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behavior, so they land GREEN; RED-first ordering does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalized to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterization.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per project convention (AmE spelling is universal in MTConnect.NET canonical surfaces).

Adds tests pinning the new behavior:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from 153a487 to 3a77c59 Compare August 21, 2026 16:05
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 21, 2026
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 22, 2026
…RFC 4122 variant bits

Coverage-FLOOR characterization tests — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behavior, so they land GREEN; RED-first ordering does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalized to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterization.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 22, 2026
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per project convention (AmE spelling is universal in MTConnect.NET canonical surfaces).

Adds tests pinning the new behavior:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch 2 times, most recently from f42fa43 to 09def57 Compare August 22, 2026 08:57
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 22, 2026
…n values

Adopts the Ultrareview cycle 1 findings on the AgentUuid three-path
resolver introduced earlier in this PR:

* Reject the all-zero `Guid.Empty` value in `TryValidate`. Guid.TryParse
  is happy to accept "00000000-0000-0000-0000-000000000000" in every
  supported format, but adopting it as an agent's meta-device UUID would
  collide every agent in a fleet on the same identifier — RFC 4122
  requires uniqueness "for the resource's entire lifetime".
* Redact operator-supplied and persisted values from the fallback
  warning messages. The prior sanitized-echo approach still leaked up
  to 64 characters of a mispasted API key, bearer token, or password
  in the AgentUuid config slot, and only stripped CR/LF for
  log-injection defense (NEL, Unicode LINE / PARAGRAPH SEPARATOR, ANSI
  CSI, and other C0 control bytes passed through). Emitting only
  `length=N` closes both surfaces without a partial guard.
* Delete the `SanitiseForLog` helper — there is no longer any raw
  value to sanitize, so its rename target, the truncation ellipsis,
  and every log-injection edge case are moot.
* Hoist the duplicate `TryValidate(persistedUuid, …)` call so the
  fallback-kind label ("persisted"/"derived") and the Path 2 branch
  share one parse.
* Rewrite the `AgentUuidResolver` and `TryValidate` XML-doc rationale.
  The prior "fails XSD validation on every typed enum/decimal DataItem"
  claim is inaccurate — every `UuidType` in the shipped v1.5, v1.8, and
  v2.7 device schemas is `xs:restriction base="xs:string"` with no
  pattern, so the schema silently accepts a non-UUID value. The
  normative anchors are the Part 1 prose "for its entire life" contract
  and cppagent parity; the doc now says so.
* Update `docs/reference/configuration.md` — both `agentUuid` rows now
  describe the accepted formats, the validation and length-only warn
  contract, and the three-path fallback order.
* Update `AgentUuidValidationTests` to match the redacted warn format
  (length assertion + never-echoes-raw-value + control-character
  log-safety guard, over an expanded parametric input set covering
  CR/LF/NEL/LINE-SEP/PARA-SEP/NUL/ANSI/TAB and paste-in-wrong-field
  secret shapes). Add a parametric case pinning `Guid.Empty` rejection
  across every Guid.TryParse format.
* Format-fix trailing whitespace introduced on the two PR-touched
  source files that dotnet-format flagged.
…RFC 4122 variant bits

Coverage-FLOOR characterization tests — closes the boundary / bit-layout / matrix
gaps left after PR TrakHound#220's initial pass. All tests characterise
already-correct behavior, so they land GREEN; RED-first ordering does not apply to pure coverage-pin commits.

AgentUuidValidationTests.cs (+144 LOC):
  - TryValidate leading/trailing whitespace (space, tab, CRLF) is
    trimmed by Guid.TryParse — pin the delegated contract so a swap
    to Guid.TryParseExact would fail the harness.
  - TryValidate mixed-case hex accepted and normalized to lowercase
    (companion to the uppercase test).
  - TryValidate interior control / whitespace (NUL, CRLF, space, tab
    embedded in the middle) is rejected — outer-only trim contract.
  - TryValidate overlong (valid prefix + 200-char tail) is rejected —
    full-string match required.
  - TryValidate trailing CRLF+injected-text is rejected — parse layer
    refuses the classic log-injection payload shape even though the
    warn redaction guard already closes the log-line-forgery risk.
  - Resolve valid override + malformed persisted → Path 1 short-circuits;
    no warn is emitted for the malformed persisted value. Closes the
    3x3 override/persisted matrix cell not covered by the existing
    warn-count assertions.

AgentUuidDeterministicDefaultTests.cs (+79 LOC):
  - DeriveFromSeed output has the RFC 4122 variant high bits set to
    0b10 in octet 9 (clock_seq_hi_and_reserved). Extends the sibling
    version-digit test to a full RFC 4122 §4.3 bit-layout characterization.
  - Derive port change (5000 vs 8080) produces a different UUID for
    the same agent name — pins the "agent:name:port" seed contract.
  - Derive port: 0 sentinel does NOT collide with port: 1 — pins the
    sentinel's uniqueness so a regression that treats 0 as "omit"
    cannot silently collide with a real port-1 deployment.
…Derive guard

Applies the fix-worthy findings from the PR TrakHound#220 Ultrareview cycle:

- F-DOC-001 / F-DOC-002 (HIGH): update stale XML doc summaries on
  AgentApplicationConfiguration.AgentUuid + IAgentApplicationConfiguration.AgentUuid
  to mirror the PR220 three-path resolution semantics. Regenerating
  docs/reference/configuration.md via MTConnect.NET-DocsGen picks up the
  new prose and closes the Configuration_Page_Is_In_Sync_With_Source
  docs-sync test failure that the pre-hardening XML docs caused.
- F-IMP-001 (MEDIUM): DeterministicAgentUuid.TryValidate trims surrounding
  whitespace before parsing so a trailing newline / YAML indent /
  copy-paste padding does not silently reject an otherwise-valid UUID;
  the local trim also keeps the length cap defense meaningful against
  padded input and isolates the resolver from any future .NET runtime
  tightening around Guid.TryParse's implicit trim.
- F-SEC-002 (LOW): TryValidate rejects inputs longer than 72 characters
  (longest RFC 4122 textual form + slack) before invoking Guid.TryParse
  so a pasted-in mega-payload cannot cost megabytes of parse state.
- F-IMP-002 (MEDIUM): MTConnectAgentApplication.StartAgent emits an Info
  log line with the resolved meta-device UUID so operators no longer
  have to reproduce the resolver's three-path decision from
  configuration state during field-support triage.
- F-IMP-004 (LOW): DeterministicAgentUuid.Derive throws ArgumentException
  when both agentName and hostname are null / empty so a misconfigured
  caller cannot silently produce a fleet-wide constant UUID.
- F-CR-004 (LOW): AgentUuidResolver.Resolve warn message broadened to
  "not an acceptable RFC 4122 UUID (must be non-empty, parseable, and
  not the all-zero nil UUID)" so operators debugging a Guid.Empty
  rejection do not chase a parse failure that never happened —
  Guid.Empty IS RFC 4122 §4.1.7-defined but rejected as a fleet-wide
  collision hazard.
- F-CR-002 / F-CR-003 (LOW): AmE typography drift closed in
  AgentUuidResolver.cs comment + three AgentUuidValidationTests.cs test
  method identifiers (normalised → normalized) and one XML-doc cross-ref
  (behaviour → behavior, parenthesised → parenthesized) per project convention (AmE spelling is universal in MTConnect.NET canonical surfaces).

Adds tests pinning the new behavior:

- TryValidate_input_one_past_length_cap_is_rejected — 73-char input
  boundary.
- TryValidate_mega_payload_is_rejected_before_parse — 10 KB DoS defense.
- Resolve_warn_on_nil_uuid_uses_broad_acceptable_wording — Guid.Empty
  warn wording pin.
- Derive_throws_when_both_agent_name_and_hostname_are_empty — 4 cases
  covering the [null,null] / [null,""] / ["",null] / ["",""] matrix.
- Derive_accepts_null_or_empty_hostname_when_agent_name_supplied — 2
  cases confirming the non-empty-name path still succeeds.

Runs on top of test-coverage-audit's c0d9f54 boundary/enum/variant pin.
@ottobolyos
ottobolyos force-pushed the fix/agent-uuid-lifecycle-hardening branch from d3f8410 to bd7d93a Compare August 23, 2026 02:58
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 23, 2026
@ottobolyos
ottobolyos marked this pull request as ready for review August 25, 2026 21:41
@PatrickRitchie
PatrickRitchie merged commit 0ddc3c6 into TrakHound:master Aug 26, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this from Reviewing to Done in MTConnect.NET-Development Aug 26, 2026
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 26, 2026
…nit4 rebase

Rebasing onto upstream/master (PR TrakHound#220 merge) pulled in
AgentUuidValidationTests.cs, whose bare lambda arguments to
Assert.DoesNotThrow / Assert.Throws are ambiguous between the
TestDelegate and Action overloads once NUnit is upgraded to 4.x.
TestDelegate is obsolete-as-error in NUnit 4, so cast to Action
explicitly at the three call sites instead.
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
…ation/up-to-pr-222

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
…ion/up-to-pr-225

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
…ion/up-to-pr-226

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
…ation/up-to-pr-227

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
…tical) into integration/up-to-pr-228

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
…ion/up-to-pr-229

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
…o integration/up-to-pr-232

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
… integration/up-to-pr-233

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
…tegration/up-to-pr-223

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
…integration/up-to-pr-224

Cascade rebuild after upstream/master advanced to 0ddc3c6 (PR TrakHound#220 merge).

# Conflicts:
#	MTConnect.NET.sln
#	build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs
#	build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumStringDescriptions.scriban
#	build/MTConnect.NET-SysML-Import/Xml/Templates/XmlCuttingToolLifeCycle.scriban
#	libraries/MTConnect.NET-Common/Assets/CuttingTools/Measurement.g.cs
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 26, 2026
…-pr-239

Cascade rebuild after upstream/master advanced to 0ddc3c6 (PR TrakHound#220 merge).

# Conflicts:
#	tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7DataItemTypeTests.cs
#	tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonConditionsArrayShapeTests.cs
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 26, 2026
…ntegration/up-to-pr-241

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
…to integration/up-to-pr-249

Cascade rebuild after upstream/master advanced to 0ddc3c6 (PR TrakHound#220 merge).

# Conflicts:
#	libraries/MTConnect.NET-Common/Configurations/AgentConfiguration.cs
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 26, 2026
…integration/up-to-pr-261

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
…nit4 rebase

Rebasing onto upstream/master (PR TrakHound#220 merge) pulled in
AgentUuidValidationTests.cs, whose bare lambda arguments to
Assert.DoesNotThrow / Assert.Throws are ambiguous between the
TestDelegate and Action overloads once NUnit is upgraded to 4.x.
TestDelegate is obsolete-as-error in NUnit 4, so cast to Action
explicitly at the three call sites instead.
ottobolyos added a commit to ottobolyos/mtconnect.net that referenced this pull request Aug 27, 2026
…nit4 rebase

Rebasing onto upstream/master (PR TrakHound#220 merge) pulled in
AgentUuidValidationTests.cs, whose bare lambda arguments to
Assert.DoesNotThrow / Assert.Throws are ambiguous between the
TestDelegate and Action overloads once NUnit is upgraded to 4.x.
TestDelegate is obsolete-as-error in NUnit 4, so cast to Action
explicitly at the three call sites instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants