Wire ApplyScaling, StorageRate; close out write-commands plan

ApplyScaling (HistorianTagDefinition.ApplyScaling):
The EnsT2 trailer's second byte controls server-side scaling — `FE 00`
mirrors MinRaw to MinEU and sets AnalogTag.Scaling=0; `FE 01` persists
distinct MinRaw/MaxRaw and sets Scaling=1. Decoded by toggling
set_ApplyScaling on the native harness and capturing the wire bytes for
both values with identical inputs. The earlier docs claimed
EnsureTagAsync needed a follow-up "UpdateTags" call; the WCF surface has
no such operation — toggling that one byte is the whole fix.

StorageRate (HistorianTagDefinition.StorageRateMs):
Serializer accepts a non-default rate, validated empirically against
the live server which only accepts quantized values
(1000/5000/10000/60000/300000 ms).

EnsureTagAsync upsert semantics:
Second call on the same tag name with different fields succeeds and
updates Description, MinEU, MaxEU, MinRaw, MaxRaw, Scaling in place
(verified by direct SQL inspection in a live test).

Plan + doc closeout:
write-commands-reverse-engineering.md rewritten as a current-state
plan with three workstreams (A doc closeout / B idempotency / C1
StorageRate) and a parallelism table; prior phase notes preserved as
appendix. handoff.md, implementation-status.md, wcf-contract-evidence.md,
README.md updated to remove "writes are out of scope" / non-existent
UpdateTags references and document the actual EnsT2 wire format
including the `FE xx` trailer.

Reverse-engineering harness gains --write-apply-scaling and a SQL
post-check that prints the persisted AnalogTag bounds so future RE
sessions can verify wire→DB causality without leaving the harness.

169/169 tests pass (was 165; +4 new tests covering ApplyScaling,
StorageRate golden bytes, StorageRate live persistence, and
EnsureTagAsync upsert semantics).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-04 22:04:27 -04:00
parent a175c6e5a0
commit 5ce62a5900
13 changed files with 561 additions and 721 deletions
+15 -9
View File
@@ -5,13 +5,13 @@ production SDK has no dependency on `aahClientManaged.dll`, `aahClient.dll`, or
any other AVEVA native runtime — the wire protocol is reverse-engineered and
re-implemented in C#.
Read-only by design. The required surface (per [`CLAUDE.md`](CLAUDE.md)):
The supported surface (per [`CLAUDE.md`](CLAUDE.md)):
| Operation | Status |
|---|---|
| `ProbeAsync` | live-verified |
| `ReadRawAsync` | live-verified |
| `ReadAggregateAsync` | live-verified (TimeWeightedAverage; other modes need fixtures) |
| `ReadAggregateAsync` | live-verified across all 16 retrieval modes |
| `ReadAtTimeAsync` | live-verified |
| `ReadEventsAsync` | live-verified (typed event + 31-property property bag) |
| `BrowseTagNamesAsync` | live-verified |
@@ -19,8 +19,13 @@ Read-only by design. The required surface (per [`CLAUDE.md`](CLAUDE.md)):
| `GetConnectionStatusAsync` | synthesized from authenticated probe (matches native semantic) |
| `GetStoreForwardStatusAsync` | synthesized defaults (no SF sidecar to probe) |
| `GetSystemParameterAsync` | live-verified via `Stat/GetSystemParameter` |
| `EnsureTagAsync` | live-verified for analog Float/Double/Int2/Int4/UInt4; `ApplyScaling=true` persists distinct MinRaw/MaxRaw |
| `DeleteTagAsync` | live-verified |
Out of scope: write-back, store-forward write, configuration changes.
Out of scope: writing samples (`AddS2` is architecturally blocked — the server's
runtime cache only ingests from configured IOServer / Application Server
pipelines), store-forward write, configuration changes, discrete/string tag
creation (native `AddTag` rejects them).
## Quick start
@@ -160,9 +165,10 @@ property dictionary → Retr.EndEventQuery → Hist.Close2
## Status
124 unit + live integration tests pass (`dotnet test --logger "console;verbosity=minimal"`).
Full read-only SDK surface verified end-to-end against both a local Historian
(`LocalPipe`) and a remote Historian (`RemoteTcpIntegrated` over Net.TCP with
Windows transport auth). `RemoteTcpCertificate` ProbeAsync is live-verified;
the other ops over the certificate transport plus the explicit-credentials
path await live verification.
165 unit + live integration tests pass (`dotnet test --logger "console;verbosity=minimal"`).
Full SDK surface — reads, browse, metadata, status, plus the two write ops
(`EnsureTagAsync` / `DeleteTagAsync`) — verified end-to-end against both a
local Historian (`LocalPipe`) and a remote Historian (`RemoteTcpIntegrated`
over Net.TCP with Windows transport auth). `RemoteTcpCertificate` ProbeAsync
is live-verified; deeper coverage over the cert transport plus the
explicit-credentials path await additional verification.