Plan: docs/plans/speculative-items-sweep.md (also covers parallelism + findings). Implemented: - C3: HistorianTagDefinition.IntegralDivisor (default 1.0). Wire bytes flip per the captured native serializer; live probe shows the server stores IntegralDivisor on EngineeringUnit (shared) rather than per-tag, so the value is accepted on the wire but doesn't visibly persist for the test EU. Documented in the property's doc-comment. - E: HistorianWcfCertOptionTests (5 tests) covering AllowUntrustedServer- Certificate validator installation + ServerDnsIdentity propagation through CreateEndpointAddress and CreateBindingPair. Investigated + documented (deferred): - D3: Discrete/String/Int1/Int8/UInt8 EnsT2 root cause — server-side ValidationFailed: "Transaction validation failed". Native AddTag's validator rejects non-analog types; not a wire-format issue. To unlock, need to capture a working native flow via a different code path (likely SMC's tag-import path or AddTagExtendedProperties carrying type-specific metadata). Defer until a customer asks. - D1: AddTagExtendedProperties feasibility — managed surface confirmed (ArchestrA.HistorianAccess.AddTagExtendedProperties + WCF op AddTagExtendedPropertyGroups). Cost estimated at 1-2 days of focused RE work due to CTagExtendedPropertyGroup payload complexity. Defer. - D2: AddRevisionValuesBegin/Value/End — sub-plan written at docs/plans/revision-write-path.md with 5-step capture sequence, workstream estimates, and risk register. Implementation deferred. 177/177 tests pass (was 172; +5 cert tests + 1 IntegralDivisor unit test, harness probe results not committed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.0 KiB
Plan: Speculative Items Sweep (2026-05-04)
The five items I previously called out as speculative / deferred. Goal: exercise the cheap ones, investigate the medium ones to feasibility, and write sub-plans for anything too big to ship in one push.
Items
| ID | Item | Effort | Touches |
|---|---|---|---|
| C3 | Expose IntegralDivisor on HistorianTagDefinition |
small | HistorianTagDefinition.cs, HistorianTagWriteProtocol.cs, orchestrator, tests |
| E | Unit tests for AllowUntrustedServerCertificate / ServerDnsIdentity |
small | new test file under tests/ |
| D3 | Root-cause Discrete/String/Int1/Int8/UInt8 EnsT2 failure | medium (investigation) | native harness, possibly serializer |
| D1 | Capture wire bytes for AddTagExtendedProperties |
medium (capture + decode) | native harness, possibly new serializer + public API |
| D2 | Implement AddRevisionValuesBegin/Value/End (revision-write path) |
large | new orchestrator + 3 new public APIs |
Parallelism
Concurrency-safe groupings (each pair is independent at the file level):
- C3 ↔ E — C3 touches
HistorianTagDefinition.cs+HistorianTagWriteProtocol.cs+ orchestrator + integration tests; E adds a new test file + might add a small unit-test util. No file overlap. - D3 ↔ D1 — Both touch the native trace harness Program.cs, so they conflict if done concurrently. Sequence them.
- C3/E ↔ D3/D1 — No file overlap; can run concurrently with the harness work.
- D2 stands alone (different code paths entirely).
In a single-agent session, the order is:
- C3 (small, predictable) — land first
- E (small, predictable) — land second
- D3 (investigation; documents findings whether or not implementation is possible)
- D1 (investigation + capture; same pattern)
- D2 — write a focused sub-plan; do NOT implement in this sweep
Success Criteria
- C3:
HistorianTagDefinition.IntegralDivisor(default 1.0) plumbed through serializer; unit test asserts non-default value flips the wire bytes; live test asserts the value persists inTag.IntegralDivisor(or wherever it lands in SQL). - E: 2-3 unit tests asserting
HistorianWcfClientCredentialsHelper.ConfigureandHistorianWcfBindingFactory.CreateEndpointAddresshonor the new options. - D3: documented root cause + decision (workable path / not workable / requires further capture). If a workable path emerges quickly, also implement.
- D1: documented evidence summary + decision (worth implementing / defer / requires customer ask).
- D2:
docs/plans/revision-write-path.md(or similar) with the 5-step capture sequence + open questions.
Findings
C3 — IntegralDivisor (executed 2026-05-05)
Plumbed through serializer + orchestrator; default 1.0. Unit test verifies
the 8-byte double immediately preceding the trailer flips with a non-default
value. Live probe: server accepts the wire bytes but IntegralDivisor
appears to be stored on EngineeringUnit (shared across all tags using that
EU) rather than per-tag, and the EU's stored value didn't change for the
test. Documented in the property's doc-comment. No live integration test
added (nothing to assert in SQL).
E — Cert option unit tests (executed 2026-05-05)
Added HistorianWcfCertOptionTests (5 tests) covering:
Configureis a no-op whenAllowUntrustedServerCertificate=falseConfigureinstalls the accept-any validator +RevocationMode.NoCheckwhen the option is trueCreateEndpointAddresswith no DNS identity returns an address withIdentity == nullCreateEndpointAddresswith a DNS identity attaches aDnsEndpointIdentityCreateBindingPair(RemoteTcpCertificate)propagatesServerDnsIdentityto the History endpoint (and not to the Retrieval endpoint, which uses plain MdasNetTcp without TLS)
D3 — Discrete/String/Int1/Int8/UInt8 EnsT2 root cause (investigated 2026-05-05)
Probed each unsupported type via the native trace harness with
--write-data-type {Type}. Result for SingleByteString and Int1 (others
truncated in the same output):
HistorianAccess.AddTagreturnsSuccess=false,TagKey=0- Error:
ErrorCode=ValidationFailed,ErrorType=CustomError,ErrorDescription="Transaction validation failed"
Conclusion: The failure is server-side, not wire-format. The
/Hist.EnsT2 server-side validator rejects non-analog types when invoked
through the AddTag → EnsT2 code path. To unlock these types from the SDK
we'd need to:
- Capture a successful native creation of a discrete/string tag via some
other mechanism (likely SMC's tag-import path or a different WCF op
like
AddTagExtendedPropertiescarrying the discrete/string-specific metadata) - Diff the working native flow against the failing one to see what ancillary fields the validator expects (TagType vs CDataType, separate StorageType, IO-server pre-registration, etc.)
Decision: defer until a customer asks. The native AVEVA wrapper itself
cannot create these tags via AddTag from a managed client — implementing
this would require RE work on a path the wrapper doesn't exercise, which
is much higher risk than the existing analog write surface.
D1 — AddTagExtendedProperties feasibility (investigated 2026-05-05)
Managed surface confirmed. Native API:
- Public managed entry point:
ArchestrA.HistorianAccess.AddTagExtendedProperties(token0x0600619B, 140 IL instructions, 6 locals) - WCF op:
CHistoryConnectionWCF.AddTagExtendedPropertyGroups(token0x0600405C) - Underlying contract method:
IHistoryServiceContract2.AddTagExtendedProperties(already declared in our reproduced contracts) - Managed input type:
HistorianTagExtendedPropertyGroupwrapping the nativeCTagExtendedPropertyGroupC++ class. Built from astd::vector<CTagExtendedPropertyGroup>(visible in the IL locals). Property group structure not yet decoded.
Decision: defer implementation. Cost estimate:
- Reflect-construct
HistorianTagExtendedPropertyGroupvia the native harness (probably 2-4 hours — these C++/CLI types often have hidden constructor requirements that surface only at runtime). - Call
AddTagExtendedPropertieswith a sandbox group; capture wire bytes viainstrument-wcf-writemessage(1 hour). - Decode the
CTagExtendedPropertyGrouppayload — this is its own struct that needs walking field-by-field against the native serializer IL (token0x06002038,CHistStorage.AddTagExtendedProperties) (3-6 hours). - Implement managed
HistorianTagExtendedPropertyGroupmodel + serializer- public
AddTagExtendedPropertiesAsyncAPI + tests (4-6 hours).
- public
Total: 1-2 days of focused work. Defer until a customer asks for tag extended properties or the analog write surface needs them as a prerequisite.
D2 — AddRevisionValuesBegin/Value/End
Sub-plan deferred to a dedicated session — see
docs/plans/revision-write-path.md (created in this sweep).
Out of scope for this sweep
Refactoring HistorianWcfTagClient to respect options.Transport for browse / metadata (i.e., let it use cert binding from Windows). Worth doing but not part of the speculative-items list.