Files
lmxopcua/tests/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests.csproj
T
Joseph Doherty f0082af5b9 build(analyzers): wire OTOPCUA0001 tree-wide + triage the surfaced hits (arch-review 07/C-1)
Inject the custom UnwrappedCapabilityCallAnalyzer as an OutputItemType=Analyzer
ProjectReference from Directory.Build.props (excluding the analyzer + its test
project) so OTOPCUA0001 runs on every src/ and tests/ compilation — it previously
enforced its CapabilityInvoker-wrapping rule against nothing but its own 31 unit
tests (the 'built-but-never-wired' failure mode).

Triage of the ~280 surfaced hits, three categories:

1. RESILIENCE-DISPATCH-GAP (7 sites, DriverInstanceActor x6 + GenericDriverNodeManager
   x1): a REAL, previously-untracked gap the analyzer caught on first wiring — the
   Phase 6.1 CapabilityInvoker resilience pipeline (retry/breaker/bulkhead/telemetry)
   is constructed ONLY in tests and was never wired into the production dispatch
   layer. Scoped per-site #pragma with a greppable RESILIENCE-DISPATCH-GAP marker
   explicitly noting these are tracked-but-not-intentional, pending the dispatch-wiring
   remediation (filed as a follow-up). Keeps the analyzer live everywhere else in
   those projects so a NEW unwrapped call still fails the build.

2. Driver-INTERNAL self-calls (3 sites, AbCipAlarmProjection x2 + S7Driver x1):
   a driver's own poll/ack path calling its own capability method. The invoker wraps
   the driver from the dispatch layer OUTWARD; a driver re-wrapping its own internal
   calls would double-wrap. Genuinely intentional — scoped #pragma with that rationale.

3. Wire-level test suites + manual-testing CLIs (12 projects): invoke drivers directly
   by design — the analyzer's own documented intentional case. Project-level NoWarn
   with a comment.

Verified: full solution build green, 0 OTOPCUA0001 hits; analyzer's 31 tests pass;
negative control — dropping one dispatch-gap pragma re-fires OTOPCUA0001 and fails
the Runtime build, proving the analyzer is genuinely live tree-wide, not disabled.
2026-07-08 17:51:19 -04:00

32 lines
1.4 KiB
XML

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<RootNamespace>ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.Tests</RootNamespace>
<!-- OTOPCUA0001 (arch-review 07/C-1): these tests invoke ScriptedAlarmSource's IAlarmSource
methods DIRECTLY to exercise its wire-level behavior, which is the analyzer's own documented
intentional case ("a unit test invoking the driver directly ... move the suppression into a
NoWarn for the test project"). Genuinely intentional — not a resilience-dispatch gap. -->
<NoWarn>$(NoWarn);OTOPCUA0001</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3"/>
<PackageReference Include="Shouldly"/>
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
<PackageReference Include="xunit.runner.visualstudio">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Core\ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms\ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms.csproj"/>
</ItemGroup>
</Project>