7e4d713eb3
HistorianSspiClient rewritten on top of System.Net.Security.NegotiateAuthentication
in place of P/Invoke into secur32.dll's InitializeSecurityContextW. The class
keeps the same Next() / Dispose() / two-constructor surface so callers don't
change. RequiredProtectionLevel=EncryptAndSign + AllowedImpersonationLevel=
Identification produces a request-flag set equivalent to the captured native
0x2081C / 0x81C bitmasks (still preserved as constants for the existing unit
tests). Removes the only Windows P/Invoke in the production SDK; the
[SupportedOSPlatform("windows")] gating elsewhere stays in place pending a
separate sweep.
HistorianStorageType (Cyclic = 1, Delta = 2):
Captured 2026-05-04 via --write-storage-type on the harness. Delta differs
from Cyclic in three places — header byte 10 (0x02 -> 0x06), flag-block
byte 1 (0x01 -> 0x02), and 4 zero bytes inserted after StorageRate before
the FILETIME. Server persists Tag.StorageType=1/2 accordingly. Plumbed
through HistorianTagDefinition.StorageType + serializer + orchestrator + 2
new tests (golden bytes + live SQL persistence verification).
Docs polish:
CLAUDE.md no longer claims "no P/Invoke" (HistorianSspiClient is the one
allowed P/Invoke surface); updated test count to 169+; AGENTS.md Required
SDK Surface and Repository Layout brought up to date with the live state
including the write surface; handoff.md "not a git working tree" obsolete
note removed.
171/171 tests pass with the NegotiateAuthentication replacement (was 169;
+2 new tests for StorageType).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
231 lines
8.0 KiB
Markdown
231 lines
8.0 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 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/`.
|