Files
lmxopcua/docs/plans/2026-10-11-issue-batch-674-678-design.md
T
2026-10-11 10:39:01 -04:00

4.5 KiB
Raw Blame History

Follow-up batch #674–#678 — design (2026-10-11)

Follow-ups filed after the #667–#673 batch. Base: master bc03adb1. User-approved; recommended choices throughout. Investigation found three new defects (client endpoint port not rewritten; role overlays never load on cluster-role nodes; Gateway Count/Average mode mapping) — the first two are fixed here, the third is filed.

Lane Scope Model
L1 #674 HistoryUpdate posture opus
L2 #675 reverse event paging opus
L3 #677 aggregates opus
L4 client (#677.5, #678.5/.6, #674.6) sonnet
L5 #676 OpcUaClient opus
L6 #678.1–.4 + role-overlay bug sonnet

L1 — #674

  • 674.1: spike on QuestDB 10.0.1 showed TTL is judged against min(maxTs, wall clock) (cairo.ttl.use.wall.clock=true default) — a 2066 row evicted nothing. Add a QuestDB integration test pinning that + a docs note. HistoryUpdate refuses a SourceTimestamp beyond now + ServerHistorian:HistoryUpdateMaxFutureSkew (default 1 day) with BadOutOfRange; the recorder is not bounded.
  • 674.2: SqlServer base schema requirement back to v1; SupportsModifiedTrail (v ≥ 2). On v1: modified reads and HistoryUpdate ⇒ BadHistoryOperationUnsupported (nothing sent), retention skips SampleModified, one Warning per boot.
  • 674.3: HistoryUpdate Primary-gated (off-Primary ⇒ BadInvalidState, same shape as NativeAlarmAckPrimaryGate). Retry duplicates on QuestDB documented; no DEDUP key.
  • 674.4/674.5 documented only.

L2 — #675

  • Reverse event reads: reverse flag on IHistorianDataSource.ReadEventsAsync; SqlServer/QuestDB order DESC and take the top N; direction-aware cursor (reuse raw SliceTieCluster(reverse:)); Gateway ⇒ BadHistoryOperationUnsupported for reverse.
  • End-only event read ⇒ backward (mirrors raw).
  • Offline test pinning DateTime.MaxValue through the Gateway proto/FILETIME encoding; live AVEVA leg stays open (VPN).

L3 — #677

  • Reverse processed reads per SDK/Part 13: buckets anchored at the later (start) time stepping back, partial bucket earliest, bucket timestamp = later edge. Parity test vs SDK AggregateCalculator. Client-visible, release-noted.
  • Partial bit also when the data starts inside a bucket (no bounding prior).
  • AggregateConfiguration: UseServerCapabilitiesDefaults or values equal to the server defaults ⇒ served; otherwise per-node BadAggregateConfigurationRejected.
  • Gateway provisioner sends IntegralDivisor = 1 (proto3 default 0). Live magnitude check stays open (VPN).

L4 — client

  • EndpointSelector.SelectBest rewrites host and port of the advertised endpoint (fixes rig :4841 cert error).
  • Client aggregate enum/mapper/CLI/UI gain TimeAverage, TimeAverage2, Total, Total2, Interpolative.
  • History read refusal ⇒ one-line CommandException, no stack trace.
  • NodeManagerHistoryReadTests non-historized case sets IsReadModified=false.

L5 — #676

  • Driver endpoint host+port rewrite; in-process TCP-stall proxy wire test (in-place blip, same session, Good republish, no regression).
  • Remove dead ReconnectPeriod (options, AdminUI form, docs, tests); stored JSON with it still parses.
  • New opt-in IDriverConnectionLossSource (Core.Abstractions): raised once per session by OpcUaClient only on a definitive loss (BadSessionIdInvalid/BadSessionClosed/BadSessionNotActivated/subscription lost); DriverInstanceActor (attach PreStart, detach PostStop) turns it into DisconnectObserved only while Connected. Ambiguous codes keep going through the #527 watchdog.
  • Information-level per-recovery replay-drop summary. Equal-timestamp drop documented.

L6 — small

  • Retention: mid-command cancel test + ClearPool fallback test with falsification control.
  • #672 tests: initial-state unreachable path; strengthen Self_unreachable_is_ignored; edge-triggered Debug log.
  • FOCAS WireBackendTests: wait for motor speeds too; WaitFor fails on timeout.
  • QuestDB TTL-cleared log wording; docker-dev/docker-compose.debug.yml Debug recipe.
  • Role overlay suffix built from plain roles only — after auditing each appsettings.<role>.json and stripping anything that would change production behaviour on activation.

Live gates (docker-dev)

  1. opc-plc docker restart recovers in seconds (was ~100 s); pause-blip re-check.
  2. Client.CLI connects to :4841–:4845.
  3. HistoryUpdate refused on the Secondary, accepted on the Primary; v1-schema DB keeps historizing.
  4. Reverse event paging and reverse processed reads over the wire, SqlServer + QuestDB.