Commit Graph

100 Commits

Author SHA1 Message Date
Joseph Doherty
b88c75c116 docs(plans): track Task 19 follow-ups (site DI cleanup, sandbox API, SourceScript) 2026-05-19 02:35:47 -04:00
Joseph Doherty
435c853dce docs(plans): track SMTP-helper deduplication follow-up 2026-05-19 01:33:21 -04:00
Joseph Doherty
dff9e0aa76 docs(plans): code implementation plan for the notification outbox
26 TDD tasks across six phases — data layer, message contracts, the new
ScadaLink.NotificationOutbox project (actor, dispatcher, Email adapter),
site S&F retarget and central wiring, Central UI, and verification.
2026-05-19 00:39:10 -04:00
Joseph Doherty
f2513a4ef4 docs(notification-outbox): fix stale message-pattern count and tree alignment 2026-05-18 23:52:10 -04:00
Joseph Doherty
c8b8cd9150 docs(notification-outbox): merge duplicate S&F dependency bullet, standardize cross-ref 2026-05-18 23:48:59 -04:00
Joseph Doherty
bb35453d58 docs(notification-outbox): fix stale cross-references after outbox addition 2026-05-18 23:45:43 -04:00
Joseph Doherty
097bb3361e docs(notification-outbox): polish Task 8 docs — purge basis, message-contract naming, density 2026-05-18 23:34:40 -04:00
Joseph Doherty
ef4614d710 docs(notification-outbox): clarify purge is a repository operation, not job ownership 2026-05-18 23:32:07 -04:00
Joseph Doherty
bb5519f6f2 docs(notification-outbox): add Notifications table, entity, and message contracts 2026-05-18 23:30:16 -04:00
Joseph Doherty
d7a16084b5 docs(notification-outbox): add Notification Outbox page to Central UI 2026-05-18 23:25:41 -04:00
Joseph Doherty
f2d710a9dc docs(notification-outbox): add Notification Submission communication pattern 2026-05-18 23:22:33 -04:00
Joseph Doherty
0dd3be0bd8 docs(notification-outbox): trim Site Event Logging notification row, de-duplicate rationale 2026-05-18 23:21:23 -04:00
Joseph Doherty
a59f5ec1ff docs(notification-outbox): add Notification category to Site Event Logging 2026-05-18 23:19:27 -04:00
Joseph Doherty
6ccf3766dc docs(notification-outbox): add central-computed outbox KPIs to Health Monitoring 2026-05-18 23:17:07 -04:00
Joseph Doherty
0b56c809e1 docs(notification-outbox): polish S&F naming consistency and prose 2026-05-18 23:15:59 -04:00
Joseph Doherty
b83d16364a docs(notification-outbox): retarget S&F notification category to central 2026-05-18 23:13:17 -04:00
Joseph Doherty
2a7e7289b3 docs(notification-outbox): polish Notification Service prose and heading scope 2026-05-18 23:12:02 -04:00
Joseph Doherty
0f96562bfd docs(notification-outbox): central-only Notification Service, typed lists, async API 2026-05-18 23:09:29 -04:00
Joseph Doherty
a4ba2dfe01 docs(notification-outbox): fix naming consistency and status-lifecycle clarity 2026-05-18 23:07:17 -04:00
Joseph Doherty
0388720390 docs(notification-outbox): add Component-NotificationOutbox design doc 2026-05-18 23:04:17 -04:00
Joseph Doherty
f177b58699 docs(plans): implementation plan for the notification outbox
11 bite-sized documentation tasks covering the new component doc and
revisions across the affected component docs, README, and CLAUDE.md,
with a final cross-reference consistency sweep.
2026-05-18 23:01:30 -04:00
Joseph Doherty
bbfa0c515e docs(plans): fold refinement decisions into notification outbox design
Resolves the six open questions: host-level forward-retry config,
Notify.Status returns a status record, 10-min stuck threshold, a
site-local Forwarding state, site-side logging of forward failures
only, and point-in-time KPIs computed from the Notifications table.
2026-05-18 22:57:45 -04:00
Joseph Doherty
d4e86c1b1d docs(plans): design for central notification outbox
Captures the basic design for a reliable notification outbox: sites
store-and-forward notifications to the central cluster, which logs
them to a type-agnostic Notifications table (single audit source) and
delivers them via per-type adapters with retry, parking, and KPIs.
2026-05-18 22:54:17 -04:00
Joseph Doherty
06462a0100 feat(template-engine): contained names for composition-derived templates
A composition-derived template now stores its contained name — the
composition slot's InstanceName (e.g. "Pump"), unique only within its
owner — instead of the dotted global path ("Motor Controller.Pump").
The qualified hierarchical name is computed on read.

- TemplateNaming.QualifiedName: walks the OwnerCompositionId chain to
  build the dotted path; null-safe, cycle-guarded.
- TemplateConfiguration: the unique index on Template.Name becomes
  filtered (WHERE IsDerived = 0) — base templates stay globally unique;
  derived templates' uniqueness is the existing (TemplateId,
  InstanceName) index on TemplateComposition.
- Migration ContainedDerivedTemplateNames: rewrites derived rows to the
  contained name; Down rebuilds the dotted names via a recursive CTE
  before restoring the global index.
- TemplateService: composition create/rename store the contained name;
  the dotted-name collision pre-checks and cascade-rename are removed
  (a slot rename no longer touches nested derived templates).
- TemplateEdit: title shows the contained name; the qualified path is a
  breadcrumb subtitle; "composed inside" uses the owner's qualified name.

TDD: 4 TemplateNaming tests + updated composition tests. TemplateEngine
293, ConfigurationDatabase 114, CentralUI 316 green. Migration applied to
the dev cluster and verified in the browser (Motor Controller.Pump now
titled "Pump"; nested Motor Controller.Pump.TempSensor resolves).

Design: docs/plans/2026-05-18-contained-template-names-design.md
2026-05-18 17:50:30 -04:00
Joseph Doherty
2d4b287ab2 docs(plans): design for contained names on composition-derived templates 2026-05-18 17:37:43 -04:00
Joseph Doherty
437fe154e7 feat(triggers): add WhileTrue fire mode for Conditional/Expression script triggers
Conditional and Expression script triggers gain an optional `mode` field
in their TriggerConfiguration JSON:

- OnTrue (default): unchanged edge/per-change firing. An absent mode field
  parses as OnTrue, so every existing trigger config behaves identically.
- WhileTrue: fires on the false->true edge, then re-fires on a periodic
  timer while the condition holds; stops on the true->false edge. The
  re-fire cadence is the script's MinTimeBetweenRuns; with none configured
  the trigger degrades to a single edge fire and logs a warning.

ScriptActor tracks condition truth state and manages a dedicated
"whiletrue-trigger" timer. ScriptTriggerConfigCodec and ScriptTriggerEditor
round-trip the mode and expose an OnTrue/WhileTrue selector for the two
trigger kinds. Design: docs/plans/2026-05-18-whiletrue-trigger-mode-design.md

Tests: 7 ScriptActor runtime tests (edge fire, timer re-fire, stop,
re-arm, no-MinTimeBetweenRuns degrade, OnTrue regressions) + 14 codec /
editor tests. SiteRuntime suite 206 green, CentralUI suite 295 green.
2026-05-18 10:44:11 -04:00
Joseph Doherty
19870d1f8f docs(plans): design for WhileTrue conditional/expression trigger mode 2026-05-18 10:30:22 -04:00
Joseph Doherty
c583598888 fix(deployment-manager): resolve DeploymentManager-013 — document SMTP-credential artifact handling as a conscious accepted design decision 2026-05-16 23:49:25 -04:00
Joseph Doherty
a2f6c1b9b2 fix(inbound-api): resolve InboundAPI-007 — remove unimplemented Database.Connection() script API from design doc (conflicts with script trust model) 2026-05-16 23:49:25 -04:00
Joseph Doherty
3d0c1c6963 fix(host): resolve Host-002 — REQ-HOST-6 doc corrected to drop unused Akka.Persistence requirement 2026-05-16 23:49:25 -04:00
Joseph Doherty
84a696b0e4 fix(security): resolve Security-009,010,011 — LDAP connection timeout, design-doc correction, security-path test coverage; Security-008 deferred 2026-05-16 22:24:03 -04:00
Joseph Doherty
7d1cc5cbb4 fix(configuration-database): resolve ConfigurationDatabase-005,006,008,009,010,011 — bounded gRPC columns, split queries, CSV-parse logging, null guards, coverage 2026-05-16 22:14:23 -04:00
Joseph Doherty
c07f524ca4 fix(commons): resolve Commons-005..007,009..012 — OPC UA parse status, TryConvert correctness, Result null guard, invariant formatting, doc refresh 2026-05-16 22:04:21 -04:00
Joseph Doherty
738e67acc5 fix(cli): resolve CLI-002..007 — robust response rendering, URL/JSON arg validation, credential env-vars, doc refresh 2026-05-16 20:58:03 -04:00
Joseph Doherty
cac8aebe9f docs(cluster-infrastructure): resolve ClusterInfrastructure-001 — document that the Host owns the Akka bootstrap 2026-05-16 20:12:24 -04:00
Joseph Doherty
8050a1996f docs(plans): implementation plan for expression triggers 2026-05-16 05:25:10 -04:00
Joseph Doherty
c94d3b7570 docs(plans): design for expression-based script & alarm triggers
Captures the brainstormed design for a new Expression trigger: a read-only
boolean C# expression evaluated on attribute updates, edge-triggered for
scripts and level-based for alarms, compiled against a restricted read-only
globals type.
2026-05-16 05:21:57 -04:00
Joseph Doherty
7044791a55 docs(plans): scrub LmxProxy references from design plans
Remove the LmxProxy work package (WP-8) from phase-3b, the CD-DCL-1..6
protocol details, Q9/Q-P3B-2 from the questions log, the LmxProxy
component-design rows in requirements-traceability, and the inline
mentions across phase-0, phase-4, the gRPC streaming plans, and the
primary/backup data-connection plans.
2026-05-13 13:30:07 -04:00
Joseph Doherty
751248feb6 feat(alarms): HiLo trigger type with per-band level, hysteresis, messages, overrides
Adds a new HiLo alarm trigger type with four configurable setpoints
(LoLo / Lo / Hi / HiHi). Each setpoint carries an optional priority,
deadband (for hysteresis), and operator message. The site runtime emits
AlarmStateChanged with an AlarmLevel field so consumers can differentiate
warning vs critical bands.

Plumbing:
  - new AlarmLevel enum + AlarmStateChanged.Level/Message init properties
  - AlarmTriggerEditor (Blazor) gets a HiLo render with severity tinting
  - AlarmTriggerConfigCodec extracted from the editor for testability
  - sitestream.proto carries level + message over gRPC
  - SemanticValidator enforces numeric attribute, setpoint ordering,
    non-negative deadband
  - on-trigger scripts get an Alarm global (Name/Level/Priority/Message)
    so notification routing can branch by severity
  - per-instance InstanceAlarmOverride entity + EF migration + flattening
    step + CLI commands; HiLo overrides merge setpoint-by-setpoint, binary
    types whole-replace
  - DebugView shows a Level badge + per-band message tooltip
  - App.razor auto-reloads on permanent Blazor circuit failure
  - docker/regen-proto.sh automates the proto regen workflow (the linux/arm64
    protoc segfault means generated files are checked in for now)
2026-05-13 03:23:32 -04:00
Joseph Doherty
783da8e21a feat(ui): structured editors for script schemas and alarm triggers
Replace raw-JSON text inputs with rich UI: script parameter/return types use
a JSON Schema builder (SchemaBuilder + JsonSchemaShapeParser, with a migration
to convert existing definitions); alarm trigger config uses a type-aware
editor with a flattened attribute picker (AlarmTriggerEditor). AlarmActor
gains optional direction (rising/falling/either) on RateOfChange triggers.
2026-05-13 00:33:00 -04:00
Joseph Doherty
552c9e4065 docs(templates): record phase 4-9 completion + verification TODOs
All nine derive-on-compose phases are now implemented. The status doc
captures what shipped per phase, what was deferred (LockedInDerived
override warning toast, SCADA008 base-Parent hint), and the live-DB /
UI smoke checks worth running before merge.
2026-05-12 08:59:19 -04:00
Joseph Doherty
8b8b85c839 docs(templates): record phase 2+3 completion in status doc
Phase 1 → 3 marked done; remaining work is phases 4-9. Sanity script now
targets the post-Phase-3 commit (03a8c4a) and notes the pre-existing
NU1608 build error in IntegrationTests / Host.Tests so future sessions
don't chase a phantom regression.
2026-05-12 08:31:20 -04:00
Joseph Doherty
91b786eb1c docs(templates): derive-on-compose phase status + resume plan
Companion to the design doc — captures current state, the four
decisions already made, what's done (phase 1, commit 5615f3d),
and a full play-by-play for phases 2 through 9 with exact files,
methods, and tests to touch. Written so a future session after
context compaction can pick up cleanly.
2026-05-12 08:18:43 -04:00
Joseph Doherty
a968cefbc2 docs(templates): record derive-on-compose decisions (naming, migration, tree UX) 2026-05-12 08:13:11 -04:00
Joseph Doherty
68548432b3 docs(templates): design for derive-on-compose specialization
Aveva-style composition: composing $Sensor into $Pump creates a
derived template Pump.TempSensor that inherits from $Sensor and can
override values, override script bodies, add new fields, with
LockedInDerived on the base preventing specific overrides.

Schema sketch: Template gains IsDerived + OwnerCompositionId;
TemplateAttribute/Script gain IsInherited + LockedInDerived.
TemplateComposition.ComposedTemplateId pivots to point at the
derived template (the base is reachable via derived.ParentTemplateId).

Phased rollout (9 phases), starting from additive schema, then
flow change for new compositions, then EF Core migration of
existing data, then resolution, lock semantics, tree UI, derived
template edit UI, base template lock-toggle UI, editor metadata
simplification (multi-parent picker becomes mostly obsolete —
derived templates always have a single owner).

Open questions captured at the end for review before phase 1.
2026-05-12 08:12:12 -04:00
Joseph Doherty
3ed05f0595 docs(scripts): design for template-script scope access
Self / Children / Parent accessors with sync-indexer + async-method
shape. Flattening pipeline emits ScriptScope per resolved script;
ScriptCompilationService seeds the accessors at execution time with
no new actor messages or lookup paths.

Phased: (1) runtime accessors + Scope on ResolvedScript, (2)
flattening + deploy round-trip, (3) editor metadata fetch for child
+ parent shapes, (4) Monaco completion / hover / diagnostics
(SCADA006 unknown attribute, SCADA007 unknown composition).

Out of scope: per-template Roslyn-generated typed accessors,
locking-aware writes (covered by lock-enforcement pass), and
sibling-of-sibling chained navigation.
2026-05-12 05:38:58 -04:00
Joseph Doherty
ff5f5a10ef docs(ui): UI audit findings (2026-05-12)
Audit of every page in CentralUI against the Sites.razor card-grid
pattern, the no-third-party-UI-libs constraint, and accessibility
basics. Findings + per-page severity + suggested implementation
order live in docs/plans/. Implementation follows in subsequent commits.
2026-05-12 03:31:54 -04:00
Joseph Doherty
a9c4c2c655 docs(plans): implementation plan for OPC UA config model refactor
14 bite-sized tasks (TDD pattern) covering:
- Commons foundation: POCOs, serializer, validator
- Runtime adoption: OpcUaDataConnection + DeploymentManagerActor swap
- UI build: <OpcUaEndpointEditor> + DataConnectionForm rewrite
- Verification: build/test green + Docker browser smoke + push

Tasks #45-#58 created with blocking dependencies; companion
.tasks.json sidecar persists the plan for executing-plans skill.
2026-05-12 00:33:51 -04:00
Joseph Doherty
c906e73441 docs(plans): OPC UA endpoint config model & form refactor design
Captures the design decisions from the brainstorming session:
- OpcUaEndpointConfig POCO + validator + serializer in Commons
- Single source of truth: both UI and site runtime consume the model
- Typed nested JSON storage (camelCase), legacy flat-dict fallback
- Shared <OpcUaEndpointEditor> Blazor component used twice
- Custom protocol removed from dropdown; Protocol field hidden
- Validation timing on Save only; per-field red text via ValidationEntry
2026-05-12 00:27:35 -04:00
Joseph Doherty
da5fdf0e63 feat(ui/admin): Topology-style refresh of Data Connections page
Brings the Data Connections admin page up to the same UX standard as the
Topology page:
- Search box with dim non-matches (opacity 0.4, shape preserved)
- Toolbar: + Connection (disabled until a site is selected), Refresh,
  Expand, Collapse
- Site context menu gains "Add Connection here" that navigates with
  ?siteId= so the form preselects + locks the Site field
- Form gains "Primary Endpoint" / "Backup Endpoint" h6 subsection
  headers matching the SiteForm convention; Failover Retry Count moved
  inside the Backup subsection
- URL renamed: /admin/connections (primary) + /admin/data-connections
  (legacy secondary @page). Same dual-route treatment on the form
- Nav label: "Data Connections" -> "Connections"
- Adds DataConnectionsPageTests bUnit suite (6 tests)
2026-05-11 22:42:48 -04:00