# 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 a full Git repo (origin: gitea.dohertylan.com) with the shipping SDK under `src/`, tests under `tests/`, RE tooling under `tools/`, and decoded protocol notes under `docs/`. See `CLAUDE.md` for the authoritative architecture overview. - `instructions.md` - source planning document and decision record. - `src\AVEVA.Historian.Client\` - the production managed SDK (pure .NET 10, no native AVEVA references). - `tests\AVEVA.Historian.Client.Tests\` - unit + gated live integration tests. - `tools\` - reverse-engineering tooling (CLI, native trace harness, WCF capture server, IL-rewrite instrumentation helper). - `docs\reverse-engineering\` - sanitized RE evidence and decoded notes. - `current\` - the seven DLLs the existing sidecar links against today. - `aveva-install-x64\` and `aveva-install-x86\` - full AVEVA Historian client-side DLL sets for cross-version reference. 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 The shipping public surface (all live-verified against `localhost` — see `CLAUDE.md` "Required SDK Surface" for the authoritative list and caveats): Reads: - `ProbeAsync` - `ReadRawAsync` - `ReadAggregateAsync` - `ReadAtTimeAsync` - `ReadEventsAsync` - `BrowseTagNamesAsync` - `GetTagMetadataAsync` - Status helpers: `GetConnectionStatusAsync`, `GetStoreForwardStatusAsync`, `GetSystemParameterAsync` Writes (added 2026-05-04 by explicit request): - `EnsureTagAsync` for analog Float / Double / Int2 / Int4 / UInt4 (with optional `ApplyScaling=true` for distinct MinRaw/MaxRaw and optional `StorageRateMs` for non-default sampling). - `DeleteTagAsync`. `AddS2` (write samples) is architecturally blocked — the server's runtime cache only ingests from configured IOServer / Application Server pipelines. Do not extend write support without an explicit new request. ## Reverse-Engineering Workflow The bulk of the original RE workflow has been executed and is now backed by `docs/reverse-engineering/` evidence. The notes below are the durable process in case new captures are needed (e.g., for a new Historian version or a new write op). ### 1. Managed Wrapper Analysis Use dnSpy / ILSpy / the in-repo `dnlib-method` CLI 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. Sanitized notes go under `docs\reverse-engineering\` (the folder exists and is the canonical home for committed RE evidence). ### 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 The implementation has landed and is the authoritative reference. See `CLAUDE.md` "Code Architecture" for the actual layout. The original abstract shape is preserved as historical context only. Key design rule still in force: 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 managed .NET 10. The single P/Invoke surface allowed in production is `HistorianSspiClient` (Windows SSPI for integrated auth); do not add unrelated P/Invokes. - Avoid adding native runtime dependencies to the production SDK. No reference to `aahClientManaged.dll` / `aahClient.dll` from `src/`. - Avoid broad API design. Implement only the operations listed in "Required SDK Surface". - Treat AVEVA protocol details as version-sensitive; document assumptions in `docs/reverse-engineering/`. - 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 Both the RE phase and the SDK phase are **met** as of 2026-05-04: - Managed wrapper public surface and native entry points are documented in `docs/reverse-engineering/`. - Required query flows have sanitized captures + byte-level notes; golden fixtures live under `fixtures/protocol/`. - Message framing, request/response/error layouts are decoded sufficiently for round-trip parser tests. - The shipping SDK implements the Required SDK Surface (reads + writes). - 169 unit + live integration tests pass. - Local consumers can replace the sidecar without `aahClientManaged.dll` or `aahClient.dll` at runtime. Future RE work (e.g., new Historian version, additional write ops) should follow the same workflow above; new evidence updates `docs/reverse-engineering/` and the relevant plan file under `docs/plans/`.