8 Commits
Author SHA1 Message Date
Marc Schier cdb4d82d58 Unify DI companion composition, placement and resource ownership (#4915)
# Description

DI companion models can share one address-space owner without depending
on the Machinery server pipeline or creating another DeviceSet. This
implements steps A-E of #4872.

- Add `IDiModelProvider` and neutral model registration. DI-owning
managers merge neutral providers with their family registrations, retain
each instance once by reference identity, and preserve the original
provider's type-name ordering through adapters. Robot Intent and Vision
without Assets load only their family providers because they do not own
DI. Vision's Assets dependency loader runs before neutral providers,
including providers with `Order = int.MinValue`.
- Add `AddDiModel<TProvider, TNodeManager>(configure)` with synchronous
and awaited callbacks through the existing DI post-setup pipeline. Model
registration is shared; callbacks target the selected manager type and
run in registration order. Register Machinery configuration before
dependent AutoID configuration. No registration-only AutoID/Machinery
package is needed. The existing
`OpcUaAutoIdCompositionExtensions.AddAutoIdToMachinery` API remains in
the AutoID server assembly as an obsolete forwarder to `AddAutoIdModel`.
- Centralize companion lifetime on `DiNodeManager`. Final shutdown
atomically closes registration and joins pending drains before manager
teardown, including their failures. Ordinary explicit drains permit
later batches. Machinery rearms its cached cleanup bridge when adopting
another machine-resource batch.
- Add shared DeviceSet reachability and placement helpers. Runtime DI
components link through the outermost composed component rather than
each nested device. Public organization and notifier hooks replace
companion friend-assembly access. Pumps and Scales resolve Machines
through its generated model identifier; the protected compatibility
helper remains namespace-qualified.
- Consolidate composition examples, ordering, ownership and
specification-based placement in the existing [Device Integration
guide](docs/DeviceIntegration.md#composing-companion-models). Add
summaries to the changed internal types and their public members.

The generic helper and explicit callback ordering replace the earlier
registration-only package design in response to review feedback. All
thirteen review threads have a reply describing the published correction
and are resolved.

### Validation

The latest correction passed both affected net10.0 suites and the
focused net48
regressions. Commands used `TEMP=TMP=D:\temp`, without warning
demotions:

```powershell
dotnet test tests\Opc.Ua.AutoID.Tests\Opc.Ua.AutoID.Tests.csproj -p:CustomTestTarget=net10.0 -f net10.0 -m:1 -p:BuildInParallel=false --logger trx --results-directory D:\temp\issue4872-feedback2-net10.0 -v quiet --no-restore
# Passed 358; exit 0.
dotnet test tests\Opc.Ua.Vision.Tests\Opc.Ua.Vision.Tests.csproj -p:CustomTestTarget=net10.0 -f net10.0 -m:1 -p:BuildInParallel=false --logger trx --results-directory D:\temp\issue4872-feedback2-net10.0 -v quiet --no-restore
# Passed 713; one existing skip; exit 0.
dotnet test tests\Opc.Ua.AutoID.Tests\Opc.Ua.AutoID.Tests.csproj -p:CustomTestTarget=net48 -f net48 -m:1 -p:BuildInParallel=false --logger trx --results-directory D:\temp\issue4872-feedback2-net48 -v quiet --filter 'FullyQualifiedName~LegacyMachineryRegistration'
# Passed 2; exit 0.
dotnet test tests\Opc.Ua.Vision.Tests\Opc.Ua.Vision.Tests.csproj -p:CustomTestTarget=net48 -f net48 -m:1 -p:BuildInParallel=false --logger trx --results-directory D:\temp\issue4872-feedback2-net48 -v quiet --filter 'FullyQualifiedName~VisionFactoriesLoadNeutralProvidersOnlyWhenOwningDiAsync|FullyQualifiedName~VisionAdaptersPreserveOriginalProviderTypeNameTies'
# Passed 17; exit 0.
```


`LegacyMachineryRegistrationForwardsOptionsAndDeduplicatesTheNeutralModel`
and
`LegacyMachineryRegistrationPreservesNeutralValidation` cover the legacy
entry
point's options, provider deduplication, owner preservation and
validation.
`VisionFactoriesLoadNeutralProvidersOnlyWhenOwningDiAsync` includes four
minimum-priority Assets cases across both factories and both
registration orders.

Full-solution validation remains incomplete. The earlier net10.0 attempt
had a
Windows clipboard access failure and stopped during Stress.Tests without
a final
result. The earlier net48 solution attempt failed because target assets
were
missing; the focused commands above restore successfully. Coverage
percentages
and current CI/CodeQL results were not collected locally.

## Related Issues

Implements the proposal and maintainer answers in the tracking issue,
with the generic helper and configuration order confirmed during review.

- Fixes #4872

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [x] I have addressed **all** PR feedback received.
2026-10-27 14:34:54 +01:00
6fe5399510 Add UaLens desktop engineering workspace (#4822)
# Description

Add **UaLens**, an Avalonia desktop engineering workspace for OPC UA
exploration, monitoring, typed editing, administration and guided
companion-specification tasks.

This is a **new draft PR for `pisrapp` against `master`**, replacing
closed, unmerged #4462 without reopening it. The shared prerequisites
(#4801, #4802, #4803, #4804 and #4806) have all merged; their
implementation is no longer part of this PR's delta.

### Scope

- Multi-document workspace with connection, security and identity
controls; browsing, subscriptions, events, alarms, history, writes and
method calls.
- Offline NodeSet2 exploration, typed scalar/array/matrix editing,
certificate/GDS and account/role tools.
- UaLens companion workflows, repository sample launching and the Aspire
AppHost.
- PubSub commissioning and capture/replay integration, plus the
UaLens-facing OpenUSD viewport and rendered Vision workflows.
- UaLens projects, test assemblies, UI assets, guides,
solution/dependency entries, desktop test wiring and delivery workflows.

Head **`6f46c51fcfef275059bbe77ef39c64c19ebc1053`** is one UaLens-only
commit directly above master
**`44a8cb277df450162c29313e2f4c862e7c683752`**. The rebase required no
conflicts. All **967 UaLens file blobs**, the full-index binary patch,
commit-message text and author/co-author attribution are unchanged from
the previously published layer. There is **no implementation delta under
`src/`**. The original history is retained in recovery refs, including
`refs/pr-stack/backups/master20261017/ualens`.

No feature was disabled, and no export/path safeguards, native
acceptance criteria, test assertions or CI gates were weakened. The four
previously recorded blank-line-at-EOF findings in the UaLens dialog
files remain unchanged; they are not reported as newly fixed.

### Validation

Fresh validation ran on the **exact PR head `6f46c51f`**, using the
existing pinned SDK **10.0.401**, normal repository analyzers and
physical/non-linked build outputs:

```powershell
$d = 'D:\git\UA-.NETStandard_master\TestResults\ualens-528-deep-repro\sdk\dotnet.exe'
$b = 'D:\git\UA-.NETStandard_master\TestResults\ua-stack-feedback20261016'
$r = 'C:\Users\mschier\.copilot\session-state\abd33a2e-7139-44e1-9912-6e4451102b4e\files\ualens-new-draft20261017-net10'
$env:DOTNET_ROOT = Split-Path -Parent $d
$env:DOTNET_ROOT_X64 = $env:DOTNET_ROOT
$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1'
$env:PATH = $env:DOTNET_ROOT + [IO.Path]::PathSeparator + $env:PATH

& $d test 'tests\Opc.Ua.Lens.Tests\Opc.Ua.Lens.Tests.csproj' --no-restore --artifacts-path $b -c Release -f net10.0 -p:CustomTestTarget=net10.0 --filter 'TestCategory!=LongRunning&TestCategory!=Stress' --logger 'trx;LogFileName=ualens-new-draft.trx' --results-directory $r --blame-hang --blame-hang-timeout 3m --blame-hang-dump-type none --verbosity minimal
# PASS, exit0: Passed: 4524, Failed: 0, Skipped: 0.
```

The saved TRX contains **4524 Passed and 44 explicit/prerequisite
NotExecuted records** (4568 total). The repository verdict helper
confirms zero failed tests, fixture setup/teardown failures or run-level
errors, without toleration. No compiler/analyzer diagnostics were
emitted. Logs, TRX and `ualens-new-draft20261017-validation.json` retain
this exact-head evidence.

**Not run for this new draft:** the full `UA.slnx` net48/net10 matrix,
fresh coverage, other desktop TFMs, application-desktop/native workflow
suites, NativeAOT, GPU/per-RID/installed-runtime or package-release
qualification. UaLens targets .NET8+; no net48 UaLens execution is
claimed. Remote CI and CodeQL are not yet claimed green. Historical
native diagnostics and successful managed tests are not substitutes for
rendered-frame or release acceptance.

The previous PR and retained session artifacts preserve the full
extraction, review, failed-attempt and diagnostic history. Historical
intermittent CI failures were not silently reclassified as root-cause
fixes; no old diagnostic grants or producer/release operations were
reused for this PR.

## Related Issues

_Reference all GitHub issues this PR addresses. If there is no issue
yet, open one and link it here._

_If this is a relatively large or complex change, a design must have
been discussed in the related tracking issue and signed off (which
becomes the Architectural Decision Record (ADR))._

- References #4461, the existing closed UaLens design/qualification
tracking issue; no new design approval is implied.
- Replaces closed, unmerged #4462 for the remaining UaLens work.
- Builds on merged prerequisites #4801, #4802, #4803, #4804 and #4806;
this PR does not close them.

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.

The test/coverage item remains unchecked because fresh coverage was not
collected. This draft does not claim CLA confirmation, full-matrix
clearance, native qualification or completed review.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Alexander Köpke <alexander.koepke@microsoft.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2026-10-21 17:18:19 +02:00
5899354441 Clarify documentation, migration guidance, and SDK selection (#4823)
# Description

Remove stock phrasing and correct misleading or inconsistent technical
documentation. The initial two passes covered 367 Markdown files,
followed by an interactive review of 169 editorial flags. The U5
interpretation originally deferred in that review has since received the
upstream Mantis answer recorded by #4843; remaining server/spec
follow-ups stay explicit in the CTT log.

- Correct package responsibilities, migration steps, API names,
ownership, protocol descriptions and links. Keep bundled migration
guides synchronized. Preserve historical conclusions as historical
records with separate re-check notes.
- Provide at least two rendered TOC levels throughout `docs/`. Convert
appropriate architecture figures to Mermaid without changing code
examples, transcripts or historical quotations.
- Address the October 19 feedback with concrete setup/migration
instructions, corrected certificate paths and PubSub names, shorter
repeated caveats, consistent XML comments, and a full review of the
Concepts guide. Retain #4839's API corrections.
- Integrate #4841's runtime/performance guidance and review
incoming/recent prose. Preserve dated measurements rather than claiming
new benchmark runs; clarify allocation ratios, startup-only processor
settings, JIT warm-up and the benchmark commit's scope. Missing raw
measurement artifacts and repeat ranges remain tracked by #4842.
- Merge master through `e8c5d800a` in `32c6394b7`. Resolve the CTT log
conflict using the updated Mantis states and OPC answers, retaining
historical framing and re-checks for C28/C32/C43.
- Address the latest naming/index feedback in `adb5bf693`: rename the
guides to `docs/WotCon.md` and `docs/WotNodeSetConversion.md`; move the
provider and DataType-declaration contracts into the conversion guide
and remove `docs/WoT.md`. Rename `samples/DI` to `samples/Di` and
`samples/Isa95` to `samples/ISA95`. Add content-index READMEs to Di,
FluentApi, ISA95, Lds and PubSub; update solution entries, project
references, Docker/CI paths, test fixture paths and documentation links
with exact casing.

**WoT guide scope.** This branch retains the detailed conversion guide
that #4758 had replaced with an anchor stub. Conversion limits, verified
document sets, preservation rules and provider ownership now live
together in `WotNodeSetConversion.md`; binding/runtime guidance remains
in `WotBindings.md` and `WotCon.md`. The design-rationale/test-ledger
prose was shortened, the oversized argument-table cell moved into its
section, and existing anchors preserved.

**SDK policy is a separate, explicit user-directed change.**
`global.json` sets a stable minimum of `10.0.400`, `rollForward:
latestMajor`, and `allowPrerelease: false`. Newer major SDKs are
permitted; CI's explicit SDK pins are unchanged. README, GettingStarted,
DeveloperGuide and Recycling instructions reflect the possible analyzer
differences. The image-contract regression fix accepts compatible stable
SDK images instead of requiring exact equality with the floor.

The latest four rename/index threads are resolved after publication.
Three older threads remain open: universal obsolete-removal timing,
unconditional nonce-strength wording, and a blanket Vision NativeAOT
claim. Existing implementation/evidence constraints are explained in
their inline replies. The two-level TOCs remain as requested.

## Validation

- `git diff --check` and staged diff checks: passed. The untouched
upstream AutoID NodeSet retains its provenance bytes, including two
existing license-header trailing spaces.
- `.\.azurepipelines\validate-migration-plugin.ps1`: passed; 15 bundled
migration documents and manifests synchronized.
- Documentation/path validation: **101** documents retain two rendered
TOC levels (**2,228** entries), with idempotent formatting. **52** new
relative links and their anchors passed exact-case checks. No tracked
references to the old guide/sample paths remain. Both relocated
provider-contract sections are preserved in the destination.
- `dotnet sln UA.slnx list`: passed; shows the renamed Di/ISA95 projects
and the existing FluentApi/Lds/PubSub projects. Updated solution and
pump ProjectReference paths also passed exact-case existence checks.
- Latest focused commands, run from the repository root:

```powershell
# Passed: 61 channel send-order and reconnect tests.
dotnet test tests\Opc.Ua.Core.Tests\Opc.Ua.Core.Tests.csproj -p:CustomTestTarget=net10.0 --filter 'FullyQualifiedName~UaSCBinaryChannelSendOrderTests|FullyQualifiedName~TcpReconnectKeyAgreementTests' --verbosity minimal

# Passed: 5 pump datasheet tests; builds the renamed pump sample.
dotnet test tests\Opc.Ua.Di.Tests\Opc.Ua.Di.Tests.csproj -p:CustomTestTarget=net10.0 --filter 'FullyQualifiedName~PumpDatasheetConformanceTests' --verbosity minimal

# Passed: 4 repository NodeSet path/round-trip tests, including the moved pump models.
dotnet test tests\Opc.Ua.Types.Tests\Opc.Ua.Types.Tests.csproj -p:CustomTestTarget=net10.0 --filter 'FullyQualifiedName~RepositorySourceSurvivesSerializedLinkedPartitionsAsync' --verbosity minimal

# Passed: build, zero warnings/errors.
dotnet build samples\ISA95\MinimalIsa95Server\MinimalIsa95Server.csproj -p:CustomTestTarget=net10.0 -f net10.0 --verbosity minimal

# Passed: dependent sample-test project build, zero warnings/errors.
dotnet build tests\Opc.Ua.WotCon.Samples.Tests\Opc.Ua.WotCon.Samples.Tests.csproj -p:CustomTestTarget=net10.0 -f net10.0 --verbosity minimal
```

Earlier focused integration checks passed 2,620 tests across AutoID,
event queues/scheduling, source generation, MCP/package profiles and
WoT. Both reviewed Mermaid diagrams rendered locally without network
access. These checks are not a full solution run.

The full solution has **not** been rerun for this review. Earlier
`dotnet test UA.slnx -p:CustomTestTarget=net10.0 --verbosity quiet` did
not pass: three AOT projects rejected VSTest and 20 Vision tests failed
during graphics initialization with `OutOfMemoryException`. Remaining
long-running tests were stopped at the user's request. A focused Vision
rerun passed 558 tests and reproduced those 20 failures. The earlier
`dotnet test UA.slnx -p:CustomTestTarget=net48 --verbosity quiet` was
blocked by the former SDK pin and was not retried after the policy
change. The user approved proceeding with those limitations documented;
current remote CI is not claimed green.

## Related Issues

- Follow-up #4842 tracks the requested 2.0.2+ benchmark/tuning and
diagnostic-tool documentation refresh. #4841 supplies documentation and
earlier results, not all newly requested measurements.
- #4758 explains the conversion guide's earlier consolidation; the
current provider contracts are now consolidated into
`WotNodeSetConversion.md`.
- #4839 supplies the reviewed API corrections; #4843 supplies the
updated CTT issue record.
- The original prose cleanup and SDK policy were user-requested without
a source issue. No new runtime architecture is introduced by these
documentation edits.

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [ ] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.

---------

Co-authored-by: Roman Ettlinger <romanett98@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:10:55 +02:00
Marc Schier 2836da7ec8 Fix sessionless ResultTransfer ownership bypass and other issues. (#4834)
# Description

Correct ownership, endpoint validation, policy propagation, subscription
delivery, file handling and generated-model behavior across the stack,
tools and samples. Add focused regression tests and update the
corresponding guides and sample documentation.

### Previously included corrections

- Require an active, matching session to generate or access transient
ResultTransfer file handles. Cover both sessionless generation and reads
against a handle owned by an active session, using live session owners
in the Machinery tests.
- Keep physical filesystem operations within their configured mount and
apply the same confinement checks throughout file operations.
- Validate LDS semaphore paths consistently during server registration
and registration-store maintenance.

### Individual issues addressed

| # | Component | Issue and correction |
|---|---|---|
| 1 | AI jobs and transfers | Jobs and transfers did not consistently
retain their creator's identity and session. Apply ownership checks to
descendants, file handles, subscriptions and execution, and recheck
deployment permissions before dispatch. |
| 2 | Password-management client | Password-bearing calls could use
signing-only channels or follow a replacement connection. Capture an
encrypted transport generation and keep dispatch bound to it; preserve
ordinary non-password edits. |
| 3 | GDS and certificate-push clients | Connections omitted hostname
verification. Validate the original configured DNS name or IP address
before session activation. |
| 4 | Certificate push | Private-key uploads could use signing-only
calls. Require an encrypted, generation-bound dispatch while preserving
certificate-only updates and restoring the caller's identity afterward.
|
| 5 | MQTT client | The .NET Framework custom-trust callback could
discard TLS hostname, certificate-availability and usage errors. Retain
those checks while supporting configured issuer trust. |
| 6 | DTLS handshake | Certificate trust was not tied to the configured
peer address. Match the certificate's DNS or IP identity to the intended
endpoint. |
| 7 | Replicated address spaces | Serialized nodes lost per-node and
descendant permission metadata. Preserve role permissions, user-role
permissions and access restrictions, including updates to existing
replica nodes. |
| 8 | MCP PubSub imports | Imports without groups skipped checks on the
effective broker destination. Check the actual endpoint before resolving
credentials or activating the connection. |
| 9 | Reference-server accounts | A disabled username account could
authenticate again with its previous roles. Reject disabled accounts
during fresh authentication. |
| 10 | Console reference client | The sample disabled hostname checks
when connecting to an otherwise trusted peer. Retain the original
requested host and validate it before activation. |
| 11 | Capture replay and export | Replay and raw export could accept
non-capture files or include key material. Require complete PCAP/PCAPNG
containers and exclude key sidecars and decryption-secret blocks. |
| 12 | PubSub adapter fallback | The fallback client configuration
automatically accepted peer certificates. Apply normal trust and
hostname validation before activation or reads. |
| 13 | Kafka transport | Explicit TLS enablement was checked but did not
reach both final Confluent configurations. Use the same effective
protocol for validation, producers and consumers. |
| 14 | PubSub actions | Configuration rebuilds could widen a
connection-local action handler's scope. Preserve its original
connection association and reject mismatched dispatch. |
| 15 | PubSub readers | Reader-level message-protection settings were
accepted but ignored. Apply the effective group and reader settings
before accepting and publishing received values. |
| 16 | PubSub key groups | Different `SecurityGroupId` values could
share one connection-wide key context. Reject mixed groups on a
connection and require separate connections for distinct groups. |
| 17 | MCP session registrations | Session-name replacement or reuse
could retain another registration's credential bindings. Bind access to
the registration, caller and authenticated endpoint, and preserve that
identity when borrowing sessions. |
| 18 | Viewer HTTP host | Requests reached the viewer's OPC UA session
without consistent Host, Origin and port checks. Validate the request
destination and browser origin before using the session, while retaining
supported local MCP clients. |
| 19 | Vision file operations | File operations did not consistently
apply protected-file checks, and remote handles lacked caller and
connection context. Apply the shared checks and use host-side opaque
handles bound to caller, target and generation. |
| 20 | DTLS record integrity | The integrity-only MAC used a truncated
sequence number. Authenticate the full reconstructed sequence number and
epoch so records remain distinct across rollover. |
| 21 | AMB client sample | Connection setup omitted hostname validation.
Preserve the originally requested host and verify the peer identity
before activation. |
| 22 | Robot sample writes | The R2 `SpeedOverride` callback could
target R1 state. Bind each callback to its own robot and apply that
robot's write policy. |
| 23 | AI result properties | Optional result children inherited
remotely writable defaults. Preserve their declaration restrictions and
keep server-produced results read-only. |
| 24 | WSS peer-trust updates | Existing channels did not consistently
respond to peer-trust changes. Revalidate complete chains for forward
and reverse WSS channels and close only those that no longer validate. |
| 25 | GDS revocation checks | Caller-provided certificates could cause
issuer retrieval from embedded URLs. Resolve validation from configured
local trust, issuers and CRLs without fetching caller-provided
locations. |
| 26 | GMS observations | Published correction observations retained
writable model defaults. Reject remote writes while preserving
publisher-side updates. |
| 27 | Production-dataset monitoring | Subscription admission and
delivery could use the reporter's context instead of each subscriber's
permissions. Evaluate the subscriber at admission and on every delivery,
including cancellation and disposal paths. |
| 28 | WoT MQTT destinations | Hostless MQTT forms could imply a
localhost destination before loopback checks. Reject them before
credential lookup or connection attempts and validate the effective
endpoint. |
| 29 | XRegistry opaque reads | Content-ID reads and notifications did
not consistently honor encrypted-read requirements or the currently
accepted transport. Recheck the bound endpoint and reject transport
downgrades before rebinding, including when protected values are already
queued. |
| 30 | PubSub capture dissection | Key loading did not consistently
check the configured capture-root boundary. Check each actual key path
immediately before opening it. |
| 31 | PubSub publication queues | Imported WriterGroup queues were not
fully checked against publish-topic grants. Check the destination
actually used by each group. |
| 32 | MCP PubSub mutations | A caller-supplied mode could select
subscribe grants for an operation that publishes. Derive the required
direction and parent context from the actual mutation. |
| 33 | Generated write masks | Model import and generation could widen
an explicit `UserWriteMask`. Preserve it through import, copy, merge,
inheritance and dependency metadata. |
| 34 | Generated method flags | An explicit `UserExecutable=false` could
be lost. Preserve its specified state and resulting method behavior
through the same model paths. |
| 35 | Generated role identifiers | Unresolved role identifiers could
cause permission entries to be omitted. Preserve namespace-qualified
role IDs and report a diagnostic when a policy cannot be represented. |
| 36 | Aggregation-server defaults | The `localhost` default did not
reliably constrain listener binding. Use numeric loopback for the
default endpoint and command-line fallback. |
| 37 | Certificate-validation cache | Cached results could skip current
leaf or issuer validity checks. Recheck validity windows on cache hits
and keep hostname validation independent of cached chain trust. |
| 38 | Software-update folders | Revision names and marker contents
containing dot segments could select paths outside the software root.
Normalize and check every derived path against that root. |
| 39 | USDA arrays | Array elements were not encoded for their string or
asset context. Escape them as data and preserve valid composition and
round-trip behavior. |
| 40 | Adapter hot reload | A changed dataset definition with the same
name could keep old fields, subscriptions or cached values active.
Compare complete immutable definitions and retire old state before
replacement. |
| 41 | Adapter index ranges | Subscription publication could ignore
`IndexRange` and return the complete value. Preserve the requested
projection and its status and timestamps; reject unsupported range
providers. |
| 42 | PubSub metadata and targets | Metadata from one connection could
change another connection's target mapping. Scope metadata to its
connection and provenance, and resolve targets using actual typed field
IDs rather than field names or unintended positional fallback. |
| 43 | Scales product locks | Product locks were not applied across
every remote mutation path. Apply them consistently to value writes,
filling calculations and related recipe/controller operations while
retaining permitted updates. |
| 44 | Event permission caching | Cached event decisions could outlive
identity, role or node-policy changes. Revalidate the current
subscriber, event type and source permissions instead of reusing a stale
decision. |
| 45 | WoT Modbus destinations | Hostless Modbus forms could imply
localhost before loopback checks. Reject them before connecting and
validate the effective endpoint. |
| 46 | MCP local PKI tools | Peer-trust mutations did not consistently
require the caller's `CertificateAdministration` grant. Check the
capability before trust and untrust operations. |
| 47 | Robot-control HTTP bridge | The bridge lacked consistent Host,
Origin and port validation and caller-specific session grants. Apply
those checks before borrowing the OPC UA session and retain supported
local clients. |
| 48 | Subscription transfers | Transferred subscriptions could retain
cached notifications after the destination's permissions changed.
Require authorization continuity between source and destination
identities and roles, invalidate stale retransmission data when
continuity fails, and preserve retransmission behavior for compatible
transfers. |

### Compatibility notes

- Replication uses the versioned NSRP v1 policy envelope. Upgrade peers
together and re-encode or reseed legacy topology from the authoritative
model; missing permission metadata is not inferred from old records.
- Integrity-only DTLS peers must be upgraded together for the full
sequence/epoch MAC. AEAD behavior is unchanged.
- Distinct PubSub key groups require separate connections.
- Custom sessions that cannot capture the actual encrypted transport,
and subscription providers that cannot honor a requested range, are
rejected rather than silently changing the requested behavior.
- Subscription transfers retain retransmission data only when the
destination authorization remains compatible with the source snapshot;
otherwise the old sequence numbers and cached data are invalidated.

## Related Issues

No separate tracking issue is linked. The individual corrections are
listed above.

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [ ] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
2026-10-21 05:37:29 +02:00
Marc Schier 7e25e1a3d7 Extract remaining shared companion, rendering and packaging changes (#4806)
# Description

The shared AI deployment contracts and instance registration; DI
software-upload outcomes, digest handling and simulator; bounded
Positioning/Pumps reads; PubSub raw-data/matrix and security-provider
handling; Vision read-quality contracts; xRegistry resource writes and
instance projection; OpenUSD authoring, embedded viewport and
retained-frame capture APIs; standalone sample CLI controls; and the
generic Debug/RID package-policy and fork/Dependabot coverage-comment
fixes. The Linux native prerequisite step is retained for **Vision tests
only**.

## Related Issues

- Related tracking issue:
[#4461](https://github.com/OPCFoundation/UA-.NETStandard/issues/4461),
without automatic closure.
- Source work:
[#4462](https://github.com/OPCFoundation/UA-.NETStandard/pull/4462),
which remains intact for the coordinator's later integration.
- Immediate stacked predecessor:
[#4804](https://github.com/OPCFoundation/UA-.NETStandard/pull/4804).

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [ ] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
2026-10-17 07:52:02 +02:00
Marc Schier 724757122b Add recycling simulator and plastics/rubber companion packages (#4772)
# Description

Add a generic, company-neutral recycling simulation sample and reusable
plastics/rubber companion-model packages. One durable causal coordinator
and ten separately launched OPC UA process views provide deterministic
material balances, finite buffers, genealogy, utilities, quality
holds/disposition, authenticated controls and crash recovery. Process
views consume committed state instead of running independent
simulations.

Real companion-model equipment instances use DI/Machinery/AMB discovery,
Machine Vision, Pumps/Scales, granulate drying, extrusion, filtration
and pelletizing. Vendor/process extensions remain sample-local.
Connectors and WoT conversion are out of scope. **External
source-contract parity and complete deployment qualification are not
claimed complete.**

The sample and managed tests target **.NET 8, 9 and 10**. The
consolidated [recycling guide](samples/Recycling/README.md) explains the
actual composition, simulation, observation paths and exposed data; the
application-directory README points to that guide.

Typed client member extensions are emitted at build time through the
default-false `ModelSourceGeneratorClientAccessorsOnly` opt-in.
Extrusion uses it for all twelve parts instead of checked-in generated
C# and a Python generator. The shared client runtime retains typed
values, quality, timestamps and streaming behavior.

### Package layout

Six packages contain fourteen models in two model-producing assemblies:

| Specifications | Model | Typed client | Server runtime |
| --- | --- | --- | --- |
| OPC 40083 and OPC 40082-6 | `Opc.Ua.PlasticsRubber` |
`Opc.Ua.PlasticsRubber.Client` | `Opc.Ua.PlasticsRubber.Server` |
| OPC 40084 parts 1–12 | `Opc.Ua.Extrusion` | `Opc.Ua.Extrusion.Client`
| `Opc.Ua.Extrusion.Server` |

NuGet IDs use the `OPCFoundation.NetStandard.` prefix. All six packages
are registered in `.azurepipelines/expected-packages.txt` and the
generated preview-pack solution. Granulate-drying code lives in
`GranulateDrying` folders in the PlasticsRubber projects; extrusion uses
per-part folders. There are no standalone granulate-drying or per-part
extrusion packages. Published model identities and CLR namespaces remain
distinct and unchanged.

The common 1.03 interface is independently authored on the explicitly
MIT-licensed 1.02 implementation basis; the official 1.03 XML is not
redistributed. The other imported models retain their individual MIT
notices. All 42 pinned model, identifier and basis files retain their
manifest-backed bytes, including their staged Git blobs. No formal
companion certification is claimed; the disputed Filter profile is not
advertised.

## Related Issues

No tracking issue is currently linked.

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [x] I have addressed **all** PR feedback received.

Current-head CI and coverage remain pending; the full local `UA.slnx`
test matrix is not claimed complete.
2026-10-15 07:00:58 +02:00
Klaus Landsdorf e0ab811c03 Scales and Machinery: advertise only the facets and units the server satisfies (#4615)
# Description

The Scales and Machinery node managers publish their facets and
conformance units through `IConformanceContributor`. This aligns what
they advertise with the published tables.

**Machinery** (`fix(machinery): advertise the ProcessIrregularity job
result unit`)
- Adds *Machinery Job Management Result ProcessIrregularity* to the
units
  reported for `WithPredefinedParameters()`. OPC 40001-3 Table 24 lists
  it, the Jobs NodeSet carries it as a `<Category>`, and
  `MachineryJobParameters` already recognises the parameter.
- New test
`PredefinedParametersAdvertiseEveryParameterUnitOfTheBaseFacetAsync`
  checks all Table 24 parameter units.

**Scales** (`fix(scales): advertise only the facets the runtime
satisfies`)
- Base Scale (and every kind facet), Scale System, Feeder Module and
  Printer Module include the Machinery Machine Identification facet
  (OPC 40200 Tables 164 to 167). While every published scale and scale
  system is organized into the `Machines` folder, the server now also
advertises that facet and its mandatory units *Machinery Find Machines*
and *Machinery Machine Identification*. When a scale is not in the
folder
  (`OrganizeIntoMachinesFolder = false`, or the folder is missing) those
facets are no longer advertised. Production preset and SI unit facets do
  not include Machine Identification and are unaffected.
- The Totalizing Hopper, Catchweigher and AutomaticWeightPriceLabeler
kind
  facets and units are no longer claimed: no controller drives them yet
(known limitations in `docs/Scales.md`). The scales still count towards
  Base Scale.
- *PackML State Information* (Table 164, optional) is advertised when a
  scale or scale system runs a PackML state machine, qualified with the
PackML namespace as the table writes it. Machinery units use namespace
0,
  as `MachineryNodeManager` reports them.
- `docs/Scales.md` updated (Machines folder, options table, conformance
  matrix, known limitations).
- New tests: `ScaleFacetsBringTheMachineIdentificationTheyIncludeAsync`,
  `ScaleFacetsAreNotClaimedOutsideTheMachinesFolderAsync`,
  `KindFacetsWithoutAControllerAreNotClaimedAsync`,
  `PackMLStateInformationIsClaimedWithAPackMLStateMachineAsync`.

Each new test fails against master and passes with the change.

Fork CI (full matrix incl. macOS) and CodeQL: green — [CI run
36779541067](https://github.com/biancode/UA-.NETStandard/actions/runs/36779541067),
[CodeQL run
36779544537](https://github.com/biancode/UA-.NETStandard/actions/runs/36779544537).

## Related Issues

- Fixes #4614

## Checklist

- [x] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
2026-10-01 15:12:44 +02:00
Klaus Landsdorf dadd609ec0 Scales: the OPC 40200 companion SDK with the OPC 30050 PackML model (#4580)
> Tracking issue #4576. #4577, #4578 and #4579 are merged, so this
branch is
> rebased onto `master` and contains only the Scales and PackML commits.

## Summary

Last of the four PRs of #4576. Adds OPC 40200 Weighing Technology 2.00
as a
model package plus a server and a client SDK, and the OPC 30050 PackML
model
it composes.

| Package | Content |
|---|---|
| `Opc.Ua.PackML` | OPC 30050 PackML 1.01, plus
`PackMLStateMachineController`, which drives a base state machine
together with its nested machine and execute state machines (activation
and deactivation of the sub-state machines, the PackML methods with an
`Executable` attribute that follows the state, acting states left
automatically or by the equipment) |
| `Opc.Ua.Scales` | OPC 40200 2.00
(`http://opcfoundation.org/UA/Scales/V2/`), generated from the
unmodified UA-Nodeset publication, plus the contracts client and server
share |
| `Opc.Ua.Scales.Server` | `AddScales()` / `ConfigureScales(...)`; all
fourteen scale kinds and scale systems below `DeviceSet` and `Machines`;
a runtime that does the weighing arithmetic (ranges, rounding to d or e,
zero band, overload/underload, zero, tare, preset tare, registration),
production presets with DI locking, statistics, recipes and recipe
files, Annex C events and alarms over a `HasNotifier` hierarchy, and the
methods of every scale type |
| `Opc.Ua.Scales.Client` | discovery, weight reads and streaming,
zero/tare/register, products, PackML state and commands, type-specific
methods, events and alarms, snapshots |

`docs/Scales.md` includes a conformance matrix against the 21 OPC 40200
server
facets with test evidence, the places where the specification and the
NodeSet disagree, and known limitations.

## Review follow-ups

Separate commits after the docs/samples commit, each with a test that
fails without it where the defect can be observed.

- Copilot review: `CurrentProductsChanged` fires only when the set of
  current products changes; the new public collection APIs
  (`ScalesServerOptions.AdditionalNamespaceUris`,
  `ScaleNamespaceIndices.SearchOrder`, `ScalesModel.AllKinds`) are
  `ArrayOf<T>`.
- Own review with the rubric in `.github/copilot-instructions.md`:
  - PackML raises `StateChanged` after its lock is released (queued, in
    order), reads `StartParameters` under the lock, and reports the
    handler's status when an acting state cannot complete.
- Scales: concurrent first creations share one runtime (the lock service
    refused a second attach); two creations of the same name cannot both
publish; a removed product id stays reserved until its node is gone; the
    zone, target-count and vehicle handlers change products under the
preset lock; the product factory and `configure` delegate run outside
    it; the recipe upload reads `ActiveRecipe` under the lock; resetting
    the statistics also resets the tolerance percentage.
- The client lets a failed browse call propagate instead of reading it
as
    "no children".

## Testing

- `tests/Opc.Ua.Scales.Tests`: 115 tests on net8 and net10 and with the
netstandard2.1 libraries, including the PackML runtime; the
client/server
  tests connect a real session over `opc.tcp` to a hosted
  `ScalesNodeManager`.
- `UA.slnx` builds for net472, net48, netstandard2.0/2.1 and net8/9/10
with
  SDK 10.0.401 and no new warnings.
- Changed-line coverage of this layer (`check-coverage.ps1`): 94.59 %
(4585 of 4847 changed lines, against `master`).
- Fork CI, full PR matrix incl. macOS: in progress, [run
36676067489](https://github.com/biancode/UA-.NETStandard/actions/runs/36676067489);
CodeQL: in progress, [run
36676070427](https://github.com/biancode/UA-.NETStandard/actions/runs/36676070427).
- On the current `master` (with Pumps merged), `UA.slnx` builds for
every target
  framework and the Scales and Pumps tests pass.
- Beyond the in-repo tests the implementation has been validated end to
end
  against a separate, non-public OPC UA client and server.

## Reviewing

Commits: PackML → Scales model → server → client → tests → docs and
samples
→ review follow-ups.
2026-09-30 10:54:48 +02:00