Phase 7 Stream E — Config DB schema for scripts, virtual tags, scripted alarms, and alarm state #183

Merged
dohertj2 merged 1 commits from phase-7-stream-e-config-db into v2 2026-04-20 19:24:55 -04:00
Owner

Adds the four tables Streams B/C/F consume. Script (generation-scoped source code), VirtualTag (generation-scoped calculated-tag config), ScriptedAlarm (generation-scoped alarm config), and ScriptedAlarmState (logical-id-keyed persistent runtime state per Phase 7 plan decision #14).

New entities (net10, EF Core)

  • Script — stable logical ScriptId carries across generations; SourceHash is the compile-cache key so Core.Scripting's CompiledScriptCache hits on re-publish of unchanged source.
  • VirtualTag — mandatory EquipmentId FK (plan decision #2, unified Equipment tree); ChangeTriggered + TimerIntervalMs + Historize flags. Check constraints: at least one trigger enabled, timer >= 50ms.
  • ScriptedAlarm — required AlarmType (AlarmCondition / LimitAlarm / OffNormalAlarm / DiscreteAlarm); Severity 1..1000 range check; HistorizeToAveva default true per plan decision #15.
  • ScriptedAlarmState — keyed ONLY on ScriptedAlarmId (NOT generation-scoped) per plan decision #14: ack state + audit trail must follow alarm identity across Modified generations. CommentsJson has ISJSON check for GxP / 21 CFR Part 11 audit.

Migration

EF-generated 20260420231641_AddPhase7ScriptingTables covers all 4 tables + indexes + check constraints + FKs to ConfigGeneration. sp_PublishGeneration required no changes — it only flips Draft → Published status; the new entities already carry GenerationId so they publish atomically with the rest of the config. Stream F's diff extension will add them to sp_ComputeGenerationDiff.

Tests — 12/12 (design-time model introspection, no SQL Server required)

Phase7ScriptingEntitiesTests covers:

  • Table registration + column maxlength + column types (Script, VirtualTag, ScriptedAlarm, ScriptedAlarmState)
  • Unique indexes: Generation+LogicalId, Generation+EquipmentPath for VirtualTag and ScriptedAlarm
  • Secondary indexes: Generation+SourceHash for cache lookup
  • Check constraints: trigger-required, timer-min, severity-range, alarm-type-enum, CommentsJson-IsJson
  • ScriptedAlarmState PK is alarm-id not generation-scoped (ack audit follows identity)
  • ScriptedAlarm defaults (HistorizeToAveva=true, Retain=true, Severity=500, Enabled=true)
  • DbSets wired on context
  • Generated migration type exists for rollforward

Next

Stream F extends sp_ComputeGenerationDiff to emit Script / VirtualTag / ScriptedAlarm sections + lights up the Admin UI Monaco editor tabs. Stream G wires the engines from Streams B+C into the DriverNodeManager dispatch path.

Adds the four tables Streams B/C/F consume. `Script` (generation-scoped source code), `VirtualTag` (generation-scoped calculated-tag config), `ScriptedAlarm` (generation-scoped alarm config), and `ScriptedAlarmState` (logical-id-keyed persistent runtime state per Phase 7 plan decision #14). ## New entities (net10, EF Core) - **`Script`** — stable logical `ScriptId` carries across generations; `SourceHash` is the compile-cache key so Core.Scripting's `CompiledScriptCache` hits on re-publish of unchanged source. - **`VirtualTag`** — mandatory `EquipmentId` FK (plan decision #2, unified Equipment tree); `ChangeTriggered` + `TimerIntervalMs` + `Historize` flags. Check constraints: at least one trigger enabled, timer >= 50ms. - **`ScriptedAlarm`** — required `AlarmType` (`AlarmCondition` / `LimitAlarm` / `OffNormalAlarm` / `DiscreteAlarm`); `Severity` 1..1000 range check; `HistorizeToAveva` default true per plan decision #15. - **`ScriptedAlarmState`** — keyed ONLY on `ScriptedAlarmId` (NOT generation-scoped) per plan decision #14: ack state + audit trail must follow alarm identity across Modified generations. `CommentsJson` has `ISJSON` check for GxP / 21 CFR Part 11 audit. ## Migration EF-generated `20260420231641_AddPhase7ScriptingTables` covers all 4 tables + indexes + check constraints + FKs to `ConfigGeneration`. `sp_PublishGeneration` required no changes — it only flips Draft → Published status; the new entities already carry `GenerationId` so they publish atomically with the rest of the config. Stream F's diff extension will add them to `sp_ComputeGenerationDiff`. ## Tests — 12/12 (design-time model introspection, no SQL Server required) `Phase7ScriptingEntitiesTests` covers: - Table registration + column maxlength + column types (Script, VirtualTag, ScriptedAlarm, ScriptedAlarmState) - Unique indexes: `Generation+LogicalId`, `Generation+EquipmentPath` for VirtualTag and ScriptedAlarm - Secondary indexes: `Generation+SourceHash` for cache lookup - Check constraints: trigger-required, timer-min, severity-range, alarm-type-enum, CommentsJson-IsJson - `ScriptedAlarmState` PK is alarm-id not generation-scoped (ack audit follows identity) - `ScriptedAlarm` defaults (HistorizeToAveva=true, Retain=true, Severity=500, Enabled=true) - DbSets wired on context - Generated migration type exists for rollforward ## Next Stream F extends `sp_ComputeGenerationDiff` to emit Script / VirtualTag / ScriptedAlarm sections + lights up the Admin UI Monaco editor tabs. Stream G wires the engines from Streams B+C into the DriverNodeManager dispatch path.
dohertj2 added 1 commit 2026-04-20 19:24:45 -04:00
Adds the four tables Streams B/C/F consume — Script (generation-scoped source code),
VirtualTag (generation-scoped calculated-tag config), ScriptedAlarm (generation-scoped
alarm config), and ScriptedAlarmState (logical-id-keyed persistent runtime state).

## New entities (net10, EF Core)

- Script — stable logical ScriptId carries across generations; SourceHash is the
  compile-cache key (matches Core.Scripting's CompiledScriptCache).
- VirtualTag — mandatory EquipmentId FK (plan decision #2, unified Equipment tree);
  ChangeTriggered/TimerIntervalMs + Historize flags; check constraints enforce
  "at least one trigger" + "timer >= 50ms".
- ScriptedAlarm — required AlarmType ('AlarmCondition'/'LimitAlarm'/'OffNormalAlarm'/
  'DiscreteAlarm'); Severity 1..1000 range check; HistorizeToAveva default true per
  plan decision #15.
- ScriptedAlarmState — keyed ONLY on ScriptedAlarmId (NOT generation-scoped) per plan
  decision #14 — ack state + audit trail must follow alarm identity across Modified
  generations. CommentsJson has ISJSON check for GxP audit.

## Migration

EF-generated 20260420231641_AddPhase7ScriptingTables covers all 4 tables + indexes +
check constraints + FKs to ConfigGeneration. sp_PublishGeneration required no changes —
it only flips Draft->Published status; the new entities already carry GenerationId so
they publish atomically with the rest of the config.

## Tests — 12/12 (design-time model introspection)

Phase7ScriptingEntitiesTests covers: table registration, column maxlength + column
types, unique indexes (Generation+LogicalId, Generation+EquipmentPath for VirtualTag
and ScriptedAlarm), secondary indexes (SourceHash for cache lookup), check constraints
(trigger-required, timer-min, severity-range, alarm-type-enum, CommentsJson-IsJson),
ScriptedAlarmState PK is alarm-id not generation-scoped, ScriptedAlarm defaults
(HistorizeToAveva=true, Retain=true, Severity=500, Enabled=true), DbSets wired, and
the generated migration type exists for rollforward.
dohertj2 merged commit e97db2d108 into v2 2026-04-20 19:24:55 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#183