Pushed on recovering the summary query params. Findings:
- Added `enum-dump` to the RE CLI (dumps a managed enum's literal members).
Confirmed INSQL_QUERYTYPE / HISTORIAN_SUMMARYTYPE are value__-only in the
managed metadata — their named members are native-side constants, so they
can't be recovered statically. Same for CColumnNameMap.LoadColumnNameMap
(column->bit built from native string/const data, not IL ldstr/ldc).
- Live-probed StartQuery2 against SysTimeSec sweeping QueryType/SummaryType/
ColumnSelectorFlags. The server ACCEPTS SummaryType 1/2/4/5 (returns a valid
version-9 buffer) but yields 0 rows; column flags don't change that;
QueryType 15/16 don't exist. So a summary query is NOT Full+SummaryType+
flags — the config lives in the AutoSummaryParameters trailer (currently
zeroed) and/or a native summary QueryType.
Conclusion recorded in the plan: the request shape needs a NATIVE capture
(instrument-wcf-writemessage on a real summary query), not managed-metadata
recovery or blind probing. Decode targets remain located. No guessed code in
src/; probe scaffolding removed. 208 tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the highest-leverage reverse-engineering primitive from the roadmap: one
path to turn a live operation buffer into a committable golden fixture. Unblocks
every capture-tier item (R0.5, R1.x, R2.1).
- ProtocolCaptureSanitizer: redacts identity-bearing values (host, tag, user,
machine) from a native buffer in BOTH ASCII and UTF-16LE, overwriting in place
with an 'X' fill so length and every field offset are preserved (keeps the
fixture useful for byte-layout RE). ASCII-letter matching is case-insensitive;
secrets < 3 chars are skipped to avoid collision corruption. AssertNoSecretsRemain
is a fail-closed safety net that refuses to emit if any value survives.
- ProtocolFixtureWriter: serializes a capture to fixtures/protocol/<op>/<name>.json
with sanitized hex, length, SHA-256 of the sanitized bytes, and a scrub report.
Timestamps are passed in (deterministic / testable).
- capture-tag-info CLI command: captures a live GetTagInfoFromName response and
writes the fixture. The same native bytes ride inside 2023 R2 gRPC
GetTagInfosFromName, so the fixture is transport-agnostic.
- 11 unit tests for the sanitizer/writer (test project now references the RE tool).
- First real fixture: get-tag-info/analog-*.json — a 98-byte Int4 CTagMetadata
buffer captured live from the local Historian 2020 server, tag name redacted,
verified to contain no identity (descriptor 03 c3 00 31 = Int4, as documented).
180 non-live unit tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>