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

71 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.