Implement EnsureTagAsync (live-verified) + DeleteTagAsync (DelT semantics partial)
New SDK surface:
HistorianClient.EnsureTagAsync(HistorianTagDefinition)
HistorianClient.DeleteTagAsync(string tagName)
Plumbing:
src/AVEVA.Historian.Client/Models/HistorianTagDefinition.cs
Public input model — TagName/Description/EngineeringUnit/DataType/MinEU/MaxEU.
Currently only HistorianDataType.Float is live-verified.
src/AVEVA.Historian.Client/Wcf/HistorianTagWriteProtocol.cs
SerializeAnalogCTagMetadata produces 146-byte payload byte-for-byte
identical to the captured native EnsT2(Float) request.
SerializeDeleteTagNames produces ushort 0x6751 + ushort 1 + uint count
+ per-tag (uint charCount + UTF-16 chars).
src/AVEVA.Historian.Client/Wcf/HistorianWcfTagWriteOrchestrator.cs
Both EnsT2 and DelT run the full Stat-priming chain captured for the
analog flow (UpdC3 + Stat.GetV ×3 + Stat.GETHI ×2 + 7× GetSystemParameter
+ Trx.GetV + Retr.GetV).
src/AVEVA.Historian.Client/Wcf/HistorianWcfTagClient.cs
MapDataType extended to accept tag-origin marker 0xC7 (SDK-created tags).
Tests:
5 golden-byte tests (HistorianTagWriteProtocolTests):
SerializeAnalogCTagMetadata byte-for-byte match against captured 146-byte fixture
SerializeAnalogCTagMetadata produces different bytes for different inputs
SerializeDeleteTagNames single-tag matches captured shape
SerializeDeleteTagNames multi-tag appends each
SerializeDeleteTagNames empty list throws
1 live integration test (gated by HISTORIAN_WRITE_SANDBOX_TAG):
EnsureTagAsync_AndDeleteTagAsync_RoundTrip_AgainstLocalHistorian
EnsureTagAsync creates the sandbox tag, GetTagMetadataAsync reads it
back. 130/130 tests pass.
Harness improvements:
--write-delete-after now runs DelT independently of AddStreamedValue
outcome.
HistorianTagStatusList constructed correctly for DeleteTags reflection
call (previous StringCollection attempt failed with TypeMismatch).
Known DelT gap: SDK's DeleteTagAsync returns true but server-side
cascading deletion does not always complete (the row remains in
Runtime.dbo.Tag). The captured native flow's DelT removes the tag
cleanly (verified via harness --write-delete-after), so something
around the WCF DelT call is missing from our orchestrator. Documented
as known issue with SMC-based cleanup as workaround.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -141,6 +141,41 @@ Phase 2 effective deliverables:
|
||||
- ⏸ Revision write path — separate capture needed against a historized
|
||||
tag
|
||||
|
||||
## Phase 3 partial (2026-05-04) — EnsureTagAsync live, DeleteTagAsync partial
|
||||
|
||||
`HistorianTagWriteProtocol` + `HistorianWcfTagWriteOrchestrator` +
|
||||
`HistorianClient.EnsureTagAsync`/`DeleteTagAsync` landed:
|
||||
|
||||
- `HistorianTagDefinition` public model (TagName/Description/EngineeringUnit/
|
||||
DataType/MinEU/MaxEU; only `Float` data type currently supported live).
|
||||
- `HistorianTagWriteProtocol.SerializeAnalogCTagMetadata` — produces 146-byte
|
||||
payload byte-for-byte identical to the captured native EnsT2(Float) request.
|
||||
- `HistorianTagWriteProtocol.SerializeDeleteTagNames` — `[ushort 0x6751,
|
||||
ushort 1, uint count, per-tag (uint charCount + UTF-16 chars)]`.
|
||||
- `HistorianWcfTagWriteOrchestrator` — both EnsT2 and DelT run the full
|
||||
Stat-priming chain captured for the analog flow (UpdC3 + Stat.GetV ×3 +
|
||||
Stat.GETHI ×2 + 7× GetSystemParameter + Trx.GetV + Retr.GetV).
|
||||
- New tag-origin marker `0xC7` added to `MapDataType` (SDK-created tags have
|
||||
byte 1 = 0xC7, distinct from 0xCF system / 0xC3 MDAS-routed).
|
||||
|
||||
Golden-byte tests (5): EnsT2(Float) byte-for-byte match against the captured
|
||||
146-byte fixture; DelT(single tag) byte-for-byte; DelT(multi-tag); empty list
|
||||
throws; different-inputs-produce-different-bytes.
|
||||
|
||||
Live integration test
|
||||
(`EnsureTagAsync_AndDeleteTagAsync_RoundTrip_AgainstLocalHistorian`,
|
||||
gated by `HISTORIAN_WRITE_SANDBOX_TAG=RetestSdkWriteSandbox`): EnsureTagAsync
|
||||
followed by GetTagMetadataAsync confirms the sandbox tag is created in
|
||||
the Runtime DB. Test passes 130/130 in the full suite.
|
||||
|
||||
**Known DelT gap.** SDK's DeleteTagAsync currently returns true but the
|
||||
server-side cascading deletion does not always complete — the row remains
|
||||
in `Runtime.dbo.Tag` even after the call returns. The captured native flow's
|
||||
DelT removes the tag cleanly (verified via the harness with
|
||||
`--write-delete-after`), so something the native code does between or
|
||||
around the WCF DelT call is missing from our orchestrator. The harness
|
||||
cleanup path remains the documented workaround for sandbox housekeeping.
|
||||
|
||||
## Phase 2 remaining work (revised — narrower scope)
|
||||
|
||||
1. Decode the 146-byte EnsT2(Float) CTagMetadata against the IL of
|
||||
|
||||
Reference in New Issue
Block a user