Files
histsdk/AGENTS.md
T
dohertj2 c95824a65d Initial commit: managed .NET 10 AVEVA Historian SDK + reverse-engineering toolkit
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>
2026-05-04 06:31:48 -04:00

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.