Commit Graph

1545 Commits

Author SHA1 Message Date
Joseph Doherty 1f7bb7ace3 feat(mgmt): secured-write approve relays to site MxGateway write with CAS race guard (T14b) 2026-06-18 02:59:43 -04:00
Joseph Doherty 74dd26eebd feat: OPC UA address-space search plumbing — actor + comm + BrowseService (T15) 2026-06-18 02:51:57 -04:00
Joseph Doherty c00c8241b3 feat(dcl): bounded recursive OPC UA address-space search adapter (T15) 2026-06-18 02:45:01 -04:00
Joseph Doherty 9ec2450ad5 feat: thread BrowseNext continuation token through actor + BrowseService (T15) 2026-06-18 02:43:25 -04:00
Joseph Doherty d5e7e897c0 feat(centralui): InstanceConfigure CSV bulk override import (T16) 2026-06-18 02:30:33 -04:00
Joseph Doherty 25c9240415 feat(mgmt): secured-write submit/reject/list handlers + Operator/Verifier gating (T14b) 2026-06-18 02:29:29 -04:00
Joseph Doherty 586d54359c feat(cli): instance import-overrides --file (T16) 2026-06-18 02:27:40 -04:00
Joseph Doherty 2cfe0de927 feat(dcl): BrowseNext continuation paging + StubOpcUaClient canned browse (T15) 2026-06-18 02:21:59 -04:00
Joseph Doherty 3c9122bc07 feat(centralui): operator Alarm Summary page + per-instance snapshot fan-out (T13) 2026-06-18 02:21:41 -04:00
Joseph Doherty 6a6f8949b9 fix(commons): OverrideCsvParser — preserve literal mid-field quotes, error on unterminated quoted field (T16 CSV) 2026-06-18 02:13:10 -04:00
Joseph Doherty c799f41d53 feat(db): PendingSecuredWrite entity + migration + repository (T14b) 2026-06-18 02:09:31 -04:00
Joseph Doherty a0ce8b6c44 feat(security): add Operator + Verifier roles + policies + LDAP mapping options (T14a) 2026-06-18 02:07:01 -04:00
Joseph Doherty 5fd77c7155 feat(dcl): surface OPC UA DataType/ValueRank/Writable on BrowseNode (T16 type-info) 2026-06-18 02:02:23 -04:00
Joseph Doherty bf1f2f6892 feat(centralui): extract AlarmStateBadges shared component from DebugView (T13) 2026-06-18 02:02:09 -04:00
Joseph Doherty 77a31ba994 feat(commons): quote-aware OverrideCsvParser (T16 CSV) 2026-06-18 02:01:38 -04:00
Joseph Doherty a87bf8a459 docs(m7): implementation plan + task graph — 22 tasks across waves A-E (T13-T17) 2026-06-18 01:57:18 -04:00
Joseph Doherty 254e0e729f docs(m7): approved design — OPC UA / MxGateway UX (T13-T17)
Full-M7 scope: operator Alarm Summary (per-instance live snapshots),
MxGateway secured writes (Operator+Verifier roles + PendingSecuredWrite +
central relay), OPC UA BrowseNext paging + bounded recursive search,
type-info surfacing + attribute-override CSV import, Verify-endpoint button +
site-local cert trust (broadcast to both nodes). Builds on the merged
opcua-tag-browser + mxgw-supervisory-write foundations already in main.
2026-06-18 01:44:40 -04:00
Joseph Doherty 241a792e7b docs(kpi): K17 — #26 KpiHistory component doc + README/CLAUDE + cross-component interactions + completion-design update 2026-06-17 20:52:12 -04:00
Joseph Doherty 3f1f4ed7c6 test(kpi): K17 — Playwright KPI trend-chart spec (tolerant, SkippableFact) 2026-06-17 20:50:23 -04:00
Joseph Doherty eb4bce3e49 refactor(kpi): K13/K15 trend review fixups — per-metric isolation, disable-during-load + logging, loading-flag finally, test coverage 2026-06-17 20:44:34 -04:00
Joseph Doherty 7d7c6cbb05 feat(kpi): K16 — Health dashboard per-site trend panel 2026-06-17 20:36:09 -04:00
Joseph Doherty 3595a41349 feat(kpi): K15 — Audit Log trend charts 2026-06-17 20:30:38 -04:00
Joseph Doherty 4a88355098 feat(kpi): K14 — Site Calls trend charts 2026-06-17 20:30:36 -04:00
Joseph Doherty 0dc819f191 feat(kpi): K13 — Notification Outbox trend charts (T11 first consumer) 2026-06-17 20:29:30 -04:00
Joseph Doherty f0177d5073 feat(kpi): K11 — KpiHistoryQueryService (scoped read + bucketing) 2026-06-17 20:21:17 -04:00
Joseph Doherty e14433cd64 feat(kpi): K5 — Host central wiring + KpiHistoryRecorder cluster singleton + appsettings (not readiness-gated)
Wire the M6 KPI History recorder into the central composition path:
- Program.cs: call services.AddKpiHistory(configuration) on the central-only
  branch alongside AddNotificationOutbox/AddAuditLog/AddSiteCallAudit.
- AkkaHostedService.cs: register KpiHistoryRecorderActor as a central,
  non-role-scoped ClusterSingletonManager + ClusterSingletonProxy + a
  PhaseClusterLeave CoordinatedShutdown graceful-stop drain (singleton name
  'kpi-history-recorder'), copied/adapted from the audit-log-purge block.
- appsettings.Central.json (Host + docker + docker-env2 central nodes): add a
  ScadaBridge:KpiHistory section (SampleInterval 00:01:00, RetentionDays 90,
  PurgeInterval 1.00:00:00, DefaultMaxSeriesPoints 200).

KPI history is observability/best-effort and MUST NOT gate readiness: the
recorder is deliberately NOT added to RequiredSingletonsHealthCheck or any
other readiness gate.
2026-06-17 20:20:34 -04:00
Joseph Doherty 601cc6f594 feat(kpi): K9 — SiteHealth sample source (per-site, from aggregator) 2026-06-17 20:20:18 -04:00
Joseph Doherty cb2a516187 refactor(kpi): K4/K10/K12 review fixups — test data-race + faulted-tick liveness, dead-branch/unused removal, NaN-guard assertions, value clamp + doc 2026-06-17 20:15:47 -04:00
Joseph Doherty 5613a5efb7 feat(kpi): K12 — reusable KpiTrendChart SVG component 2026-06-17 20:06:31 -04:00
Joseph Doherty 9c2e7ab4cb feat(kpi): K4 — KpiHistoryRecorderActor (best-effort sampling + daily purge) 2026-06-17 20:06:09 -04:00
Joseph Doherty 76f5ed72e4 feat(kpi): K10 — KpiSeriesBucketer last-per-bucket downsampler 2026-06-17 20:04:51 -04:00
Joseph Doherty e6c15250ce refactor(kpi): K2/K6/K7 review fixups — empty-batch guard + sealed repo + uniform TryAddEnumerable + KPI-age doc fidelity + coverage 2026-06-17 20:00:43 -04:00
Joseph Doherty 456e61dff3 feat(kpi): K7 — SiteCallAudit sample source 2026-06-17 19:53:49 -04:00
Joseph Doherty 6f6157ce89 feat(kpi): K8 — AuditLog sample source 2026-06-17 19:53:41 -04:00
Joseph Doherty 0d6c026dff feat(kpi): K6 — NotificationOutbox sample source (global/site/node) 2026-06-17 19:53:39 -04:00
Joseph Doherty 9ffa34d3e7 feat(kpi): K3 — KpiHistory project + options/validator + AddKpiHistory 2026-06-17 19:48:59 -04:00
Joseph Doherty cabc557629 feat(kpi): K2 — KpiSample EF mapping + KpiHistoryRepository + AddKpiSampleTable migration 2026-06-17 19:44:51 -04:00
Joseph Doherty 460777bffa feat(kpi): K1 — KpiSample + IKpiSampleSource + IKpiHistoryRepository contracts (Commons) 2026-06-17 19:40:17 -04:00
Joseph Doherty 4c6ae9da0e docs(m6): KPI History tasks.json (K1-K17 with blockedBy graph) 2026-06-17 19:32:58 -04:00
Joseph Doherty 1809664bcb docs(m6): KPI History & Trends implementation plan (K1-K17, bite-sized tasks + execution waves) 2026-06-17 19:32:58 -04:00
Joseph Doherty 6084e56c9f docs(m6): KPI History & Trends design — reusable tall/EAV KPI-history backbone + trend charts for all sources; T9/T10 (Teams) deferred to next major version 2026-06-17 19:32:58 -04:00
Joseph Doherty 59e094ada3 test(playwright): DebugViewTree — tolerate empty alarm forest (TreeView renders EmptyContent, not role=tree, when no alarms) 2026-06-17 16:08:37 -04:00
Joseph Doherty e7660134f2 fix(communication): drop IsConfiguredPlaceholder rows in StreamRelayActor before gRPC pack
Placeholder AlarmStateChanged rows are a DebugView snapshot-only concept emitted
by InstanceActor.BuildAlarmStatesSnapshot; they are never a real alarm transition.
Their timestamp may be DateTimeOffset.MinValue (the Protobuf Timestamp lower boundary),
which can throw when packed via Timestamp.FromDateTimeOffset.

Added early-return guard at the top of HandleAlarmStateChanged before any timestamp
pack or channel write. Updated the existing NativeBindingLinkage round-trip test to
use a real (non-placeholder) native alarm; added DropsAlarmStateChanged_WhenIsConfiguredPlaceholder
to assert placeholders are silently dropped (15/15 pass).
2026-06-17 15:44:28 -04:00
Joseph Doherty 7f59ae12cb test(playwright): DebugView tabs+trees — assert tabbed layout, tree panes, Alarms-tab switch on connected instance 2026-06-17 15:33:28 -04:00
Joseph Doherty ef86a2db28 refactor(debugview): cosmetic polish — test-seam comment, default-arm comment, tighten severity assertion 2026-06-17 15:30:18 -04:00
Joseph Doherty 50ce26f2e6 feat(centralui): DV-5 — Debug View tabbed composition trees (Attributes/Alarms)
Replace the two flat capped tables with a Bootstrap nav-tabs layout, each
tab hosting a TreeView<DebugTreeNode> built from the live latest-per-name
dictionaries via DebugTreeBuilder. Drop the MaxRows cap, auto-scroll locks,
and Clear buttons (change-feed affordances that don't fit a current-status
tree); HandleStreamEvent now does a plain dictionary upsert. Per-tab filters
ExpandAll on change so matches stay visible. Branch nodes surface roll-up
badges (active-count for alarms, bad-quality for attributes); native binding
nodes show active-count or 'no active conditions'. All existing badge helpers
and ValueFormatter reused. Marshalling/dispose/reconnect contract preserved
(SafeInvokeAsync/_disposed/Dispose unchanged; FilteredAttributeValues kept as
the render-thread dict reader the CentralUI-021 race test exercises).

Rework DebugViewAlarmTableTests for the tabbed-tree DOM: tab presence+default,
computed alarm grouped under its Motor1 branch with the active roll-up badge,
and a native condition nested under its source-binding node with the enriched
kind/severity/Unacked/Shelved badge set.
2026-06-17 15:23:49 -04:00
Joseph Doherty 59f135a4cf docs(DV-6): document Debug View tabbed-tree layout, native placeholders, and new AlarmStateChanged fields
- Component-CentralUI.md: replace flat-table Debug View section with tabbed
  tree layout (Attributes + Alarms tabs, TreeView<TItem> reuse, hierarchy from
  canonical names, branch roll-up, all-configured-alarms rule, native source
  binding nodes with quiet-binding placeholder rows, per-leaf rendering detail)
- Component-SiteRuntime.md (Instance Actor Wiring): add idle-binding placeholder
  emission via BuildAlarmStatesSnapshot(), _nativeAlarmKinds map, and
  NativeSourceCanonicalName stamping on live native events
- Component-SiteRuntime.md (Enriched AlarmStateChanged): document two new
  additive fields — NativeSourceCanonicalName (string?) and
  IsConfiguredPlaceholder (bool) — plus their gRPC proto fields 22/23 and
  StreamRelayActor/SiteStreamGrpcClient pack/unpack
- Component-Commons.md (Attribute Stream DTOs): extend AlarmStateChanged bullet
  with the same two additive fields and proto field numbers
2026-06-17 15:21:42 -04:00
Joseph Doherty c1e786e3fc refactor(DebugTreeBuilder): DRY BuildAttributeTree via WalkBranches; guard empty NativeSourceCanonicalName 2026-06-17 15:18:09 -04:00
Joseph Doherty 5f387ef3e3 feat(debugview): DV-4 implement BuildAlarmTree (computed leaves, native binding nodes, roll-up, filter)
Computed alarms place as leaves at their path-qualified AlarmName; native conditions group under a deduped IsNativeBinding branch keyed by NativeSourceCanonicalName with condition children keyed canonical::sourceRef. Configured-placeholder events materialise a childless binding node. Alarm roll-up (WorstState/ActiveCount) excludes placeholders. Filter matches AlarmName/SourceReference/NativeSourceCanonicalName (OrdinalIgnoreCase) and retains ancestor + binding branches. 20 new TDD cases; 18 attribute cases stay green. No DebugTreeNode model changes.
2026-06-17 15:12:57 -04:00
Joseph Doherty 69b83379d5 test(dv-3): add 4-level roll-up + deep-leaf filter tests; return AsReadOnly; add caller-contract remark
Fix 1 (Important): RollUp_FourLevelDeepBadQuality_ReachesRoot — proves bad quality at a
4-segment-deep leaf propagates HasBadQuality up every ancestor to the root.

Fix 2 (Important): Filter_DeepLeafMatch_RetainsAllAncestorBranches — proves filtering on
a terminal segment of a 3-level path retains all ancestor branches.

Fix 3 (Minor): BuildAttributeTree now returns roots.AsReadOnly() so the returned
IReadOnlyList<DebugTreeNode> reference is not a mutable list.

Fix 4 (Minor): Added <remarks> XML doc to BuildAttributeTree noting the caller-contract
that at most one AttributeValueChanged per AttributeName should be passed.

All 18 DebugTreeBuilder tests pass.
2026-06-17 15:09:01 -04:00