docs(historian-gateway): mark follow-up plan status — FU-1 documented-limitation, FU-2/3/4 done
Record the execution outcomes in the follow-up plan: FU-1 resolved as a documented protocol limitation (gateway pending.md C4; not fixable without histsdk wire-capture evidence), FU-2 done + live-validated (exact round-trip), FU-3 done (mux-ref vs historian-name decoupled via HistorizedTagRef), FU-4 done. FU-5 (pre-existing Modbus failure) and FU-6 (post-merge propagation) remain tracked. Claude-Session: https://claude.ai/code/session_012SDSQ3AcaXqPcBtDESBRii
This commit is contained in:
@@ -7,6 +7,22 @@ the live `Category=LiveIntegration` suite is green (read ✅, write-persist ✅,
|
||||
alarm-readback ⏭ skip). This doc tracks everything deliberately deferred or surfaced during
|
||||
validation, with the **owning repo** for each.
|
||||
|
||||
> **Execution update (2026-06-27 — this follow-up pass):**
|
||||
> - **FU-1 — RESOLVED as a documented protocol limitation** (NOT a fixable gateway bug): the captured
|
||||
> CM_EVENT event-send wire never carries `SourceName`, so `Source_Object` cannot be populated by the
|
||||
> gateway. Recorded as `pending.md` **C4** + a CLAUDE.md note in the HistorianGateway repo (commit
|
||||
> `174a4a9` on `fix/gateway-otopcua-followups`). The OtOpcUa live test stays skipped with the corrected
|
||||
> reason. See FU-1 below for the (now-confirmed) root cause.
|
||||
> - **FU-2 — ✅ DONE + live-validated** in HistorianGateway (`fix/gateway-otopcua-followups`, commits
|
||||
> `150868c` + `1c2d11d`). The SQL live-write path converts UTC→server-local in-SQL via
|
||||
> `DATEADD(MINUTE, DATEPART(TZOFFSET, SYSDATETIMEOFFSET()), @dt)`; an explicit-timestamp round-trip is
|
||||
> now EXACT against the live historian (delta 00:00:00).
|
||||
> - **FU-3 — ✅ DONE** in OtOpcUa (this branch, commit `111adc92`): `HistorizedTagRef(MuxRef, HistorianName)`
|
||||
> carried through the sink/recorder; interest registered by mux ref, values written under the historian
|
||||
> name. Recorder + applier tests green.
|
||||
> - **FU-4 — ✅ DONE** in OtOpcUa (this branch, commit `b2276b5b`).
|
||||
> - **FU-5** — still pre-existing/not-ours (tracked below). **FU-6** — still pending the merges.
|
||||
|
||||
**Live-validation harness recap (how to reproduce any of the live findings below):** run the
|
||||
HistorianGateway locally against the live historian, then point the OtOpcUa live tests (or `grpcurl`)
|
||||
at it. The gateway boots from env-var config (secrets from `~/.zshenv`):
|
||||
@@ -34,7 +50,15 @@ always include an `EventTimeUtc` range. `sqlcmd -S $HISTORIAN_GRPC_HOST -d Runti
|
||||
**Owning repo: `~/Desktop/HistorianGateway` (HistorianGateway).** OtOpcUa code is correct for both;
|
||||
these are gateway defects that gate the "write OtOpcUa's own data, read it back" use case.
|
||||
|
||||
### FU-1 — `SendEvent` does not populate `Source_Object` (alarm write-back-by-source)
|
||||
### FU-1 — `SendEvent` does not populate `Source_Object` — ✅ RESOLVED as a documented protocol limitation (2026-06-27)
|
||||
> **Outcome:** root-caused and confirmed **not fixable at the gateway** — the captured CM_EVENT event-send
|
||||
> wire (`HistorianEventWriteProtocol.SerializeEventValueBlob`) serializes Namespace/Type/properties but
|
||||
> **never `SourceName`** (the gateway threads it correctly; the wire drops it). `Source_Object` is a
|
||||
> Galaxy-platform association for object-raised events. Documented as `pending.md` **C4** + a CLAUDE.md note
|
||||
> in HistorianGateway; likely won't-fix (would need new wire-capture evidence in `histsdk` — vendored
|
||||
> sources aren't hand-edited). The "Investigation/Proposed fix" below is retained for the record; option 1
|
||||
> is now known to be infeasible.
|
||||
|
||||
**Symptom (live-proven):** OtOpcUa's `GatewayAlarmHistorianWriter.SendEvent` of an event with
|
||||
`source_name="HistGW.LiveTest.AlarmSource"` **acks** and **lands in `Runtime.dbo.Events`** with the
|
||||
correct `Type` (`LimitAlarm`) and `EventTimeUtc` (no shift) — but with **`Source_Object = NULL`** (and
|
||||
@@ -74,7 +98,13 @@ window. Then **un-skip** `Alarm_SendEvent_then_ReadEvents` in
|
||||
`tests/Drivers/.../Live/GatewayLiveIntegrationTests.cs` (it currently `Assert.Skip`s on a 0-result with
|
||||
the accurate reason).
|
||||
|
||||
### FU-2 — `WriteLiveValues` shifts an explicit timestamp by the local↔UTC offset (~+4h)
|
||||
### FU-2 — `WriteLiveValues` shifts an explicit timestamp by the local↔UTC offset (~+4h) — ✅ DONE + live-validated (2026-06-27)
|
||||
> **Outcome:** fixed in HistorianGateway (`fix/gateway-otopcua-followups`). The SQL live-write path now
|
||||
> converts UTC→server-local in-SQL via `DATEADD(MINUTE, DATEPART(TZOFFSET, SYSDATETIMEOFFSET()), @dt)` (a
|
||||
> single atomic offset read). An explicit-timestamp round-trip (real SQL write → gateway UTC ReadRaw) is now
|
||||
> EXACT against the live 2023 R2 historian (delta 00:00:00); offline unit test locks the exact conversion
|
||||
> expression. The OtOpcUa live write test can now be tightened (see acceptance).
|
||||
|
||||
**Symptom (live-proven, reproduces via raw `grpcurl` — no OtOpcUa code involved):** a `WriteLiveValues`
|
||||
with an **explicit** `timestamp=2026-06-27T03:45:00Z` lands in the historian at
|
||||
`2026-06-27T07:45:00Z` (+4h = the deployment's local↔UTC delta). A **server-stamped** write (null
|
||||
@@ -106,7 +136,13 @@ window anchored on the write time.
|
||||
## Priority 2 — OtOpcUa-side follow-ups
|
||||
**Owning repo: `~/Desktop/OtOpcUa` (this repo).**
|
||||
|
||||
### FU-3 — Continuous-historization `HistorianTagname` override edge case
|
||||
### FU-3 — Continuous-historization `HistorianTagname` override edge case — ✅ DONE (2026-06-27, commit `111adc92`)
|
||||
> **Outcome:** implemented the "carry both identifiers" fix below. A new `HistorizedTagRef(MuxRef,
|
||||
> HistorianName)` record threads through `IHistorizedTagSubscriptionSink` → the recorder; the recorder keeps
|
||||
> a muxRef→historianName map, registers/filters mux interest by `MuxRef` (= driver `FullName`) but writes
|
||||
> under `HistorianName` (override-or-FullName). The applier resolves both. Divergent-override + override-
|
||||
> rename-no-churn recorder tests added; applier feed tests assert the full pairs.
|
||||
|
||||
The `ContinuousHistorizationRecorder` registers `DependencyMuxActor` interest **by the resolved
|
||||
historian name** (`HistorianTagname` override else `FullName`) — the same key the EnsureTags hook and
|
||||
the writer use. The mux fans `DependencyValueChanged` **keyed by `FullReference`** (the driver's
|
||||
@@ -120,7 +156,7 @@ under the resolved historian name — i.e. carry both identifiers through `IHist
|
||||
a divergent override. **Low urgency** (overrides are uncommon); only matters for non-Galaxy historized
|
||||
tags that set an explicit `HistorianTagname`.
|
||||
|
||||
### FU-4 — `AlarmHistorianOptions.Validate()` `MaxAttempts<=0` test coverage (minor)
|
||||
### FU-4 — `AlarmHistorianOptions.Validate()` `MaxAttempts<=0` test coverage (minor) — ✅ DONE (2026-06-27, commit `b2276b5b`)
|
||||
T19 pruned the Wonderware-shaped fields and reworked `AlarmHistorianRegistrationTests`. The
|
||||
`MaxAttempts <= 0` warning branch in `AlarmHistorianOptions.Validate()` is exercised in prod but not
|
||||
covered by a test (the sibling warnings for `DrainIntervalSeconds`/`Capacity`/`DeadLetterRetentionDays`
|
||||
|
||||
Reference in New Issue
Block a user