Files
lmxopcua/scripts/queue/.partial-twincat.yaml
Joseph Doherty 2d07d716dc Recover stashed driver-gaps work from pre-v2-mxgw-merge working tree
Captures uncommitted work that lived in the working tree on
v2-mxgw-integration but was orthogonal to the migration. Stashed
during the v2-mxgw merge to master (2026-04-30) and replanted here on
a feature branch off master so it's git-visible rather than living in
the stash list.

Two distinct buckets:

1. Tracked fixture/config refinements (10 files, ~36 lines):
   - scripts/e2e/test-opcuaclient.ps1
   - src/ZB.MOM.WW.OtOpcUa.Admin/appsettings.json
   - 5 docker-compose.yml under tests/.../IntegrationTests/Docker/
     (AbCip, Modbus, OpcUaClient, S7)
   - 4 fixture .cs files (AbServerFixture, ModbusSimulatorFixture,
     OpcPlcFixture, Snap7ServerFixture)

2. Untracked driver-gaps queue artifacts (~8000 lines):
   - docs/plans/{abcip,ablegacy,focas,opcuaclient,s7,twincat}-plan.md
     — per-driver gap plans
   - docs/featuregaps.md — cross-cutting analysis
   - docs/v2/focas-deployment.md, docs/v2/implementation/focas-simulator-plan.md
   - followup.md — auto/driver-gaps queue follow-ups
   - scripts/queue/ — PR-queue automation tooling (12 files including
     pr-manifest.yaml at 1473 lines)

This commit is a snapshot for recoverability — review and split into
focused PRs (or discard) before merging anywhere downstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 08:28:01 -04:00

321 lines
13 KiB
YAML

- id: twincat-1.1
driver: twincat
phase: 1
plan_pr_id: "1.1"
title: "TwinCAT — Int64 fidelity for LINT/ULINT"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Map LInt/ULInt to DriverDataType.Int64 instead of silently truncating to Int32.
The TwinCATDataType.cs:40 truncation comment "matches Int64 gap" is removed and
MapToClrType already returns long/ulong, so the wire-level read returns the
correct boxed types. May add Int64 to Core.Abstractions DriverDataType enum if
missing. Closes a long-standing fixture caveat noted in the test suite.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs"
- "src/ZB.MOM.WW.OtOpcUa.Core.Abstractions/DriverDataType.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Primitives.TcGVL"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: S
deps: []
cross_driver: false
notes: "Hardware-gated via TWINCAT_TARGET_NETID; no e2e change to test-twincat.ps1."
- id: twincat-1.2
driver: twincat
phase: 1
plan_pr_id: "1.2"
title: "TwinCAT — TIME/DATE/DT/TOD as native UA types"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Stop marshalling IEC TIME/DATE/DT/TOD as raw UDINT and convert to native UA
Duration/DateTime types via post-processing in ReadValueAsync, ConvertForWrite,
and OnAdsNotificationEx. May expose missing Duration in DriverDataType. CLI
syntax updates so users write ISO-8601 / IEC literals instead of numeric raw
values.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Primitives.TcGVL"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: M
deps: []
cross_driver: false
notes: "Hardware-gated via TWINCAT_TARGET_NETID. May add Duration to DriverDataType enum."
- id: twincat-1.3
driver: twincat
phase: 1
plan_pr_id: "1.3"
title: "TwinCAT — Bit-indexed BOOL writes (read-modify-write)"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Replace the NotSupportedException at AdsTwinCATClient.cs:99 with read-modify-write
on the parent word, serializing concurrent bit writes to the same parent via a
keyed SemaphoreSlim. Closes referenced task #181. CLI gains an example and the
fixture caveat in the bugs-caught list updates to note writes now work.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture: []
e2e: []
effort: S
deps: []
cross_driver: false
notes: "Reuses GVL_Primitives.vWord (0xBEEF) — no fixture schema change."
- id: twincat-1.4
driver: twincat
phase: 1
plan_pr_id: "1.4"
title: "TwinCAT — Multi-dim and whole-array reads"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Expand ReadValueAsync/WriteValueAsync to handle whole-array reads in a single
AdsClient call rather than element-by-element. Surface IsArray + ArrayDimensions
on TwinCATTagDefinition and through DriverAttributeInfo from DiscoverAsync. Sets
up the array-shape plumbing the rest of the driver needs.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Arrays.TcGVL"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: M
deps: []
cross_driver: false
notes: "Hardware-gated via TWINCAT_TARGET_NETID. New 5x5 aReal2D seed with deterministic pattern."
- id: twincat-1.5
driver: twincat
phase: 1
plan_pr_id: "1.5"
title: "TwinCAT — ENUM and ALIAS at discovery"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
MapSymbolTypeName currently returns null for non-atomic types, dropping ENUM and
ALIAS symbols silently. Switch to inspecting symbol.DataType + Category from
TwinCAT.TypeSystem so DataTypeCategory.Enum walks EnumValues and Alias resolves
to base atomic recursively. Surface enum members for later EnumStrings rendering.
POINTER/REFERENCE/INTERFACE/UNION explicitly out of scope.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: M
deps: []
cross_driver: false
notes: "Reuses existing GVL_Enums + DUTs; only README integration-test contract entry added."
- id: twincat-2.1
driver: twincat
phase: 2
plan_pr_id: "2.1"
title: "TwinCAT — ADS Sum-read / Sum-write"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Replace per-tag ReadValueAsync loops with Beckhoff's ADS Sum commands
(IndexGroup 0xF080-0xF084) via SumSymbolRead/SumSymbolWrite to batch N
reads/writes per AMS request. Bucket fullReferences by DeviceHostAddress and
expose a new ReadValuesAsync surface on ITwinCATClient. Targets ~10x throughput
on multi-thousand-tag scans; perf-tier test gated behind TWINCAT_PERF=1.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ITwinCATClient.cs"
docs:
- "docs/v3/twincat-backlog.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Perf.TcGVL"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: L
deps: []
cross_driver: false
notes: "Perf test gated behind TWINCAT_PERF=1 plus TWINCAT_TARGET_NETID; new FB_PerfChurn POU."
- id: twincat-2.2
driver: twincat
phase: 2
plan_pr_id: "2.2"
title: "TwinCAT — Handle-based access with caching"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Cache CreateVariableHandleAsync results so per-read overhead drops to
read-by-handle (4-byte index vs N-byte symbol path). On
DeviceSymbolVersionInvalid (0x710) evict and retry once. Clear cache on
AdsClient reconnect until the symbol-version listener (PR 2.3) ships. Dispose
path calls DeleteVariableHandleAsync for cached handles.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture: []
e2e: []
effort: M
deps: []
cross_driver: false
notes: "Combines with PR 2.1 for sum-read-by-handle. Reuses GVL_Perf.aTags."
- id: twincat-2.3
driver: twincat
phase: 2
plan_pr_id: "2.3"
title: "TwinCAT — Symbol-version invalidation listener"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Register an AddDeviceNotificationAsync on the symbol-version index group
(AdsReservedIndexGroup.SymbolVersion 0xF008) so the handle cache from PR 2.2
is wiped on online-change bumps. Initial integration test gated as
requires-manual-online-change until automation lands. Resolves open question
(c) confirming the v6 enum constant.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
docs:
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: M
deps: ["twincat-2.2"]
cross_driver: false
notes: "Hardware-gated via TWINCAT_TARGET_NETID; manual online-change drill documented in README."
- id: twincat-3.1
driver: twincat
phase: 3
plan_pr_id: "3.1"
title: "TwinCAT — Per-tag MaxDelay tuning"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Surface NotificationSettings MaxDelay as a per-tag option (default 0 to
preserve current behavior). Plumb int? MaxDelayMs through TwinCATTagDefinition,
SubscribeAsync, and AddNotificationAsync. Coalesces high-frequency PLC signals
so the OPC UA subscription queue stops flooding under bursty change rates.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: S
deps: []
cross_driver: false
notes: "Reuses GVL_Fixture.nCounter as 100 Hz driver. Hardware-gated via TWINCAT_TARGET_NETID."
- id: twincat-3.2
driver: twincat
phase: 3
plan_pr_id: "3.2"
title: "TwinCAT — Cycle-time / jitter / PLC-state diagnostics"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Augment the probe loop to read _AppInfo.OnlineChangeCnt/AppName and
_TaskInfo[1].CycleTime/LastExecTime, surface as TwinCATDeviceDiagnostics on
DeviceState, and emit through IDriverDiagnostics (cross-driver surface from
Modbus task #154). Read system symbols directly without going through the user
browse filter.
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATSystemSymbolFilter.cs"
docs:
- "docs/drivers/TwinCAT-Test-Fixture.md"
- "docs/Driver.TwinCAT.Cli.md"
- "docs/v3/twincat-backlog.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: M
deps: []
cross_driver: true
notes: "Reuses IDriverDiagnostics from Modbus task #154. Hardware-gated via TWINCAT_TARGET_NETID."
- id: twincat-4.1
driver: twincat
phase: 4
plan_pr_id: "4.1"
title: "TwinCAT — Nested UDT browse via online type walker"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Largest single piece of work. Recurse BrowseSymbolsAsync into IStructType.SubItems
yielding one TwinCATDiscoveredSymbol per leaf with dotted instance paths. Expand
arrays-of-structs up to a configurable bound (default 1024). Add a pure
TwinCATTypeWalker helper. Folds recursed structure into Discovered/ folder tree.
Online runtime path only — TMC offline parsing deferred per open question (a).
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATTypeWalker.cs"
docs:
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
- "docs/v3/twincat-backlog.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/DUTs/ST_NestedFlags.TcDUT"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/DUTs/ST_RecursiveCap.TcDUT"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/DUTs/ST_AlarmRecord.TcDUT"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e: []
effort: L
deps: ["twincat-1.5"]
cross_driver: false
notes: "Hardware-gated via TWINCAT_TARGET_NETID. PR 1.4 helpful but not blocking."
- id: twincat-5.1
driver: twincat
phase: 5
plan_pr_id: "5.1"
title: "TwinCAT — IAlarmSource via TC3 EventLogger"
plan_anchor: "docs/plans/twincat-plan.md"
summary: |
Implement IAlarmSource over TcEventLogger on AMS port 110 so PLC alarms
surface as OPC UA AC events. Begins with a one-day spike (open question (b))
documented in docs/v3/twincat-eventlogger-spike.md to determine if a managed
wrapper exists or if we hit AMS port 110 directly via a secondary AdsClient
+ AddDeviceNotificationAsync on the alarm-list index group. Gated by new
EnableAlarms option (default false).
files:
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATAlarmSource.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs"
docs:
- "docs/drivers/TwinCAT.md"
- "docs/v3/twincat-eventlogger-spike.md"
- "docs/Driver.TwinCAT.Cli.md"
- "docs/drivers/TwinCAT-Test-Fixture.md"
fixture:
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/POUs/FB_AlarmHarness.TcPOU"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Alarms.TcGVL"
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
e2e:
- "scripts/e2e/test-twincat.ps1"
effort: L
deps: []
cross_driver: false
notes: "Hardware-gated via TWINCAT_TARGET_NETID. Spike-first; e2e Test-AlarmRoundTrip likely deferred to follow-up."