feat(template-engine): resolve TemplateEngine-002 — per-slot alarm override for derived templates
Adds IsInherited/LockedInDerived to the TemplateAlarm entity (mirroring the attribute/script override model), an EF migration, base-alarm copy-on-derive, inherited-alarm flattening skip, and LockedInDerived override-rejection validation.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
| Last reviewed | 2026-05-16 |
|
||||
| Reviewer | claude-agent |
|
||||
| Commit reviewed | `9c60592` |
|
||||
| Open findings | 10 |
|
||||
| Open findings | 9 |
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -91,7 +91,7 @@ Regression tests: `Flatten_ThreeLevelComposition_AttributesAlarmsScriptsAllResol
|
||||
|--|--|
|
||||
| Severity | High |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.TemplateEngine/TemplateService.cs:799` |
|
||||
|
||||
**Description**
|
||||
@@ -116,22 +116,25 @@ already do.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved (re-triaged 2026-05-16)._ Partially mis-stated and out of the
|
||||
current fix scope. Correction to the description: composed/inherited alarms
|
||||
are **not** dropped from the flattened deployment output — `FlatteningService`
|
||||
resolves alarms from the entire inheritance chain (`ResolveInheritedAlarms`
|
||||
walks `templateChain`, which includes the base of a derived template), so an
|
||||
instance of a derived template still receives the base template's alarms. The
|
||||
real, valid gap is narrower: there is no per-slot **alarm override**
|
||||
mechanism. The fix genuinely requires adding `IsInherited` / `LockedInDerived`
|
||||
fields to the `TemplateAlarm` entity, which lives in `ScadaLink.Commons`
|
||||
(a different module). Adding an alarm copy loop to `BuildDerivedTemplate`
|
||||
without those fields would be actively harmful: copied alarm rows on the
|
||||
derived template would shadow the live base alarm with stale data during
|
||||
flattening (`ResolveInheritedAlarms` has no `IsInherited` skip for alarms,
|
||||
unlike attributes/scripts). Resolving this safely is a cross-module change
|
||||
(`Commons` + `TemplateEngine`) and must be scheduled as a coordinated edit;
|
||||
left **Open** pending that.
|
||||
Resolved 2026-05-16 (commit `<pending>`): implemented the per-slot alarm
|
||||
override mechanism as a coordinated `Commons` + `ConfigurationDatabase` +
|
||||
`TemplateEngine` change, mirroring the existing attribute/script override
|
||||
design. Added `IsInherited` / `LockedInDerived` to the `TemplateAlarm` POCO
|
||||
(`ScadaLink.Commons`) and an EF migration `AddDerivedAlarmFields` adding two
|
||||
`bit NOT NULL DEFAULT 0` columns to `TemplateAlarms`. `BuildDerivedTemplate`
|
||||
now copies base alarms as `IsInherited = true` placeholder rows.
|
||||
`FlatteningService.ResolveInheritedAlarms` skips `IsInherited` placeholder
|
||||
rows so they no longer shadow the live base alarm, and `ValidateLockedInDerived`
|
||||
now rejects a derived override of a `LockedInDerived` base alarm.
|
||||
`UpdateAlarmAsync` honours the base `LockedInDerived` lock and persists
|
||||
`IsInherited` / `LockedInDerived`, exactly as `UpdateAttributeAsync` /
|
||||
`UpdateScriptAsync` do. Regression tests:
|
||||
`Flatten_InheritedAlarmOnDerived_BaseValueWins`,
|
||||
`Flatten_OverriddenAlarmOnDerived_DerivedValueWins`,
|
||||
`Flatten_LockedInDerivedAlarmOverride_Fails`,
|
||||
`AddComposition_CopiesAlarmsAsInherited`,
|
||||
`UpdateAlarm_LockedInDerivedBase_RejectsOnDerived`,
|
||||
`UpdateAlarm_DerivedOverride_PersistsIsInheritedFalse`.
|
||||
|
||||
### TemplateEngine-003 — `UpdateAttributeAsync` lets a non-locked attribute change its fixed DataType / DataSourceReference
|
||||
|
||||
|
||||
Reference in New Issue
Block a user