Phase 7 Stream C — Core.ScriptedAlarms (Part 9 state machine + predicate engine + IAlarmSource) #181
Reference in New Issue
Block a user
Delete Branch "phase-7-stream-c-scripted-alarms"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ships the Part 9 alarm fidelity layer Phase 7 committed to in plan decision #5. Every scripted alarm gets a full AlarmConditionType state machine with persistent operator state across restarts; runtime shape matches Galaxy + AB CIP ALMD so Phase 6.1 AlarmTracker consumes it without per-source branching.
New project
Core.ScriptedAlarmsPart9StateMachine— pure functions, immutable state. All transitions: ApplyPredicate / Acknowledge / Confirm / OneShotShelve / TimedShelve / Unshelve / Enable / Disable / AddComment / ShelvingCheck. Two structural invariants: disabled alarms ignore predicates; shelved alarms advance state but suppress emissions.AlarmConditionState— persistent record: Enabled / Active / Acked / Confirmed / Shelving + last-transition timestamps + last-ack user/comment + last-confirm user/comment + append-only Comments list (GxP / 21 CFR Part 11 audit).IAlarmStateStore+InMemoryAlarmStateStore— persistence abstraction + test default. Stream E wires a SQL backend withIAuditLogger.MessageTemplate—{TagPath}substitution at event-emission time per plan decision #13. Missing/bad/null →{?}.AlarmPredicateContext—ScriptContextsubclass for predicates. SetVirtualTag deliberately rejected at runtime (predicates must be pure).ScriptedAlarmEngine— orchestrator. Compiles predicates through Stream A sandbox, aggregates compile failures into one error, subscribes to upstream inputs AND template tokens, loads persisted state + rederives ActiveState per plan decision #14 (startup recovery). Change-trigger via per-path inverse index (no topological sort — alarms are DAG leaves). Operator actions route through state machine → persist → emit.ScriptedAlarmSource—IAlarmSourceadapter. Equipment-path prefix filter; base-interface AcknowledgeAsync routes with defaultopcua-clientuser (Stream G replaces with authenticated principal).Tests — 47 green
Part9StateMachineTests(16): every transition + state-invariants + idempotency + full lifecycle walkMessageTemplateTests(11): substitution edge cases (missing/bad/null/slashes/whitespace/multi-token/null-template)ScriptedAlarmEngineTests(13): load+subscribe, aggregated compile failures, emission on change, message resolved at emission, ack persisted, startup recovery preserves ack-but-rederives-active, shelve suppresses emission but advances state, runtime exception isolates to owning alarm, disable gates activation, add-comment audit, SetVirtualTag rejected, Dispose releases subscriptionsScriptedAlarmSourceTests(5): empty filter matches all, prefix filter, unsubscribe stops events, ack-routes-with-default-user, null rejectionFull Phase 7 test count
146 green (63 Scripting + 36 VirtualTags + 47 ScriptedAlarms). Streams D (historian sink) and G (OPC UA method wiring) consume this engine.