c95824a65d
Full read-only SDK (src/AVEVA.Historian.Client) implementing the CLAUDE.md required
surface against AVEVA Historian's binary WCF protocol — no native AVEVA runtime
dependency. All operations live-verified against a local Historian:
- ProbeAsync, ReadRawAsync, ReadAggregateAsync, ReadAtTimeAsync, ReadEventsAsync
- BrowseTagNamesAsync, GetTagMetadataAsync (17 native data-type codes mapped)
- GetConnectionStatusAsync, GetStoreForwardStatusAsync, GetSystemParameterAsync
- 108/108 unit + integration tests pass
Includes the reverse-engineering toolkit (tools/AVEVA.Historian.ReverseEngineering)
used to decode the protocol: WCF probes, IL inspection via dnlib, and IL-rewrite
instrumentation (instrument-wcf-{write,read}message etc.) plus the .NET Framework
trace harness (tools/AVEVA.Historian.NativeTraceHarness) for parity testing.
Sanitized handoff evidence under docs/reverse-engineering/. Native AVEVA binaries
(current/, aveva-install-x64/, aveva-install-x86/) are gitignored — fetch separately
from the AVEVA installer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
215 lines
6.6 KiB
Markdown
215 lines
6.6 KiB
Markdown
# AGENTS.md
|
|
|
|
## Mission
|
|
|
|
Build a fully managed .NET 10 replacement for AVEVA Historian's
|
|
`aahClientManaged` / `aahClient.dll` stack by reverse-engineering the native
|
|
binary Historian protocol.
|
|
|
|
The target is an in-process managed SDK that can replace the current .NET
|
|
Framework/native sidecar used by `OtOpcUa.Driver.Historian.Wonderware`.
|
|
|
|
## Chosen Approach
|
|
|
|
Use the reverse-engineering path from `instructions.md`:
|
|
|
|
1. Decompile `current\aahClientManaged.dll` to understand the managed wrapper
|
|
surface, connection flow, query types, data models, error handling, and
|
|
native calls.
|
|
2. Inspect `current\aahClient.dll` and the matching AVEVA install DLLs to map
|
|
the native ABI and identify transport/framing responsibilities.
|
|
3. Capture traffic from real Historian sessions and derive the on-the-wire
|
|
protocol for the required read-only operations.
|
|
4. Implement the protocol in a pure managed .NET 10 client.
|
|
|
|
Do not pursue the REST API implementation unless explicitly asked. Do not build
|
|
a P/Invoke shim as the primary solution; it is useful only as an analysis aid.
|
|
|
|
## Repository Layout
|
|
|
|
This workspace is an SDK investigation folder, not a full application repo.
|
|
|
|
- `instructions.md` - source planning document and decision record.
|
|
- `current\` - the seven DLLs the existing sidecar links against today.
|
|
- `aveva-install-x64\` - full 64-bit AVEVA Historian client-side DLL set.
|
|
- `aveva-install-x86\` - full 32-bit AVEVA Historian client-side DLL set.
|
|
|
|
Use `current\` first because it represents the deployed sidecar dependency set.
|
|
Use `aveva-install-*` to compare architecture-specific behavior and locate
|
|
adjacent client APIs.
|
|
|
|
## Required SDK Surface
|
|
|
|
Keep the managed SDK narrowly scoped to the operations used in production:
|
|
|
|
- `ReadRawAsync(tag, startUtc, endUtc, maxValues)`
|
|
- `ReadAggregateAsync(tag, startUtc, endUtc, mode, interval)`
|
|
- `ReadAtTimeAsync(tag, timestampsUtc)`
|
|
- `ReadEventsAsync(startUtc, endUtc)`
|
|
- `ProbeAsync()`
|
|
|
|
The existing alarm-event write path is dormant. Do not implement write-back
|
|
unless a new requirement is supplied.
|
|
|
|
## Reverse-Engineering Workflow
|
|
|
|
### 1. Managed Wrapper Analysis
|
|
|
|
Use dnSpy or ILSpy on `current\aahClientManaged.dll`.
|
|
|
|
Document:
|
|
|
|
- Public types and methods used for connections and queries.
|
|
- P/Invoke or native interop entry points.
|
|
- Constructor arguments, enum values, flags, and default values.
|
|
- Query argument structures for raw, aggregate, at-time, and event reads.
|
|
- Returned sample/event models, quality fields, timestamp handling, and error
|
|
propagation.
|
|
|
|
Prefer producing small Markdown notes under a future `docs\reverse-engineering\`
|
|
folder rather than relying on memory.
|
|
|
|
### 2. Native ABI Mapping
|
|
|
|
Inspect `current\aahClient.dll` and compare with:
|
|
|
|
- `aveva-install-x64\aahClient.dll`
|
|
- `aveva-install-x86\aahClient.dll`
|
|
- `aahClientCommon.dll`
|
|
- `aahDataSetClient.dll`
|
|
- `aahClientConfig.dll`
|
|
|
|
Useful tools:
|
|
|
|
- `dumpbin /exports`
|
|
- Dependencies or Process Monitor
|
|
- API Monitor
|
|
- Detours or equivalent call hooks
|
|
|
|
Document function names, calling conventions, pointer ownership, HRESULT/error
|
|
patterns, string encodings, and architecture differences.
|
|
|
|
### 3. Wire Capture
|
|
|
|
Capture real Historian sessions with Wireshark while running the existing
|
|
Wonderware sidecar/client against a development Historian.
|
|
|
|
Capture each scenario independently:
|
|
|
|
- Connection open/close and health probe.
|
|
- Raw history query.
|
|
- Aggregate query for each required retrieval mode.
|
|
- At-time/interpolated query.
|
|
- Event query.
|
|
- Error cases: bad tag, empty range, invalid credentials, server offline.
|
|
|
|
For every capture, record:
|
|
|
|
- Historian version and architecture.
|
|
- Client DLL version and file hash.
|
|
- Server host/port.
|
|
- Query parameters.
|
|
- Expected logical result set.
|
|
- Packet capture filename.
|
|
|
|
Do not commit sensitive packet captures, credentials, server names, or customer
|
|
tag names. Sanitize before adding any fixtures or notes.
|
|
|
|
### 4. Protocol Model
|
|
|
|
Derive and document:
|
|
|
|
- Session handshake.
|
|
- Authentication exchange, if present.
|
|
- Message framing and length prefixes.
|
|
- Message type identifiers.
|
|
- Request/response correlation.
|
|
- Endianness.
|
|
- Timestamp encoding.
|
|
- String encoding.
|
|
- Numeric value encoding.
|
|
- Quality/status encoding.
|
|
- Error frame format.
|
|
- Event payload format.
|
|
|
|
Add version notes whenever behavior differs between the installed 2020 DLLs and
|
|
newer Historian versions.
|
|
|
|
### 5. Managed Implementation Shape
|
|
|
|
When implementation starts, use this project shape unless the real repo dictates
|
|
otherwise:
|
|
|
|
```text
|
|
src/AVEVA.Historian.Client/
|
|
AVEVA.Historian.Client.csproj
|
|
HistorianClient.cs
|
|
HistorianClientOptions.cs
|
|
Models/
|
|
HistorianSample.cs
|
|
HistorianAggregateSample.cs
|
|
HistorianEvent.cs
|
|
RetrievalMode.cs
|
|
Protocol/
|
|
HistorianConnection.cs
|
|
HistorianFrame.cs
|
|
HistorianMessageType.cs
|
|
HistorianProtocolReader.cs
|
|
HistorianProtocolWriter.cs
|
|
Transport/
|
|
TcpHistorianTransport.cs
|
|
ClusterEndpointPicker.cs
|
|
Internal/
|
|
BackoffPolicy.cs
|
|
```
|
|
|
|
Keep protocol parsing isolated from transport I/O so captured frames can be
|
|
tested without a live Historian.
|
|
|
|
## Testing Expectations
|
|
|
|
Start with deterministic tests around protocol encoding/decoding:
|
|
|
|
- Golden byte fixtures for each message kind.
|
|
- Round-trip tests for request builders.
|
|
- Parser tests for captured and sanitized response frames.
|
|
- Timestamp, quality, and string encoding edge cases.
|
|
- Error frame parsing.
|
|
|
|
Add live integration tests only behind explicit configuration, such as:
|
|
|
|
- `HISTORIAN_HOST`
|
|
- `HISTORIAN_PORT`
|
|
- `HISTORIAN_USER`
|
|
- `HISTORIAN_PASSWORD`
|
|
- `HISTORIAN_TEST_TAG`
|
|
|
|
Integration tests must skip cleanly when these values are not configured.
|
|
|
|
## Constraints
|
|
|
|
- Keep the final SDK pure managed .NET 10.
|
|
- Avoid adding native runtime dependencies to the production SDK.
|
|
- Avoid broad API design. Implement only the operations listed above.
|
|
- Treat AVEVA protocol details as version-sensitive; document assumptions.
|
|
- Do not redistribute AVEVA binaries.
|
|
- Do not commit credentials, proprietary captures, or customer data.
|
|
- Do not delete or overwrite DLLs in `current\` or `aveva-install-*`.
|
|
|
|
## Definition of Done
|
|
|
|
For the reverse-engineering phase:
|
|
|
|
- Managed wrapper public surface and native entry points are documented.
|
|
- Required query flows have sanitized captures or byte-level notes.
|
|
- Message framing, request fields, response fields, and error frames are
|
|
described well enough to implement parser tests.
|
|
|
|
For the SDK phase:
|
|
|
|
- The managed client implements the required read-only surface.
|
|
- Unit tests cover protocol parse/build behavior.
|
|
- Integration tests can validate against a configured live Historian.
|
|
- The SDK can replace the existing sidecar call sites without requiring
|
|
`aahClientManaged.dll` or `aahClient.dll` at runtime.
|