Problem / motivation
MonitorTag produces a 0/1 alarm signal that drops back to 0 the instant its condition clears (after any hysteresis / MinDuration debounce). There is no way to make an alarm hold.
That means a self-clearing transient — a spike above threshold that returns to normal before anyone looks — is effectively invisible on a dashboard. A StatusWidget / NumberWidget bound to the monitor just shows OK, because by the time the engineer glances at the tile the signal is already back to 0. For the target user (a MATLAB sensor engineer watching a dashboard rather than the live sample stream) this is a real blind spot.
Latching / manual-reset alarms are a bedrock alarm-management pattern (ISA-18.2): an alarm, once tripped, stays asserted until an operator acknowledges it, regardless of whether the process value has since returned to normal.
Searches for latch / manual-reset against all issues return nothing — this is not yet tracked. It has surfaced as the queued #2/#3 candidate across several /feature-scout runs (2026-07-05 e/f/g) without being filed.
Proposed feature
Add an opt-in latched alarm mode to MonitorTag, plus a public reset() to clear the latch.
- New property
Latched = false (default preserves today's exact behavior).
- When
Latched = true, once the (debounced/hysteresed) signal goes to 1 it stays 1 for all subsequent samples until a reset boundary.
- New public method
reset(t) clears the latch as of time t (default: latest sample). Reset boundaries are recorded as state so getXY() stays deterministic and replayable across invalidate() / recompute().
m = MonitorTag('press_hi', st, @(x,y) y > 50, 'Latched', true);
[mx, my] = m.getXY(); % my rises to 1 on first excursion and HOLDS at 1
% even after y falls back below 50
m.reset(); % operator acknowledges -> latch clears from now on
Rough sketch
- Lib/class:
libs/SensorThreshold/MonitorTag.m only.
- FSM: the alarm pipeline is already staged — Stage 1 raw
ConditionFn, Stage 2 hysteresis (AlarmOffConditionFn), Stage 3 MinDuration debounce (see recompute_() ~L606 and applyHysteresis_() ~L682). Add a Stage 4 latch after the debounce: hold the running value at 1 once set, cleared only at recorded reset boundaries.
- Streaming: add a latch carry-in field to
cache_ (mirrors lastHystState_ / ongoingRunStart_) so appendData() preserves latch state across the append boundary.
- Public API:
Latched (logical property, NV-pair at construction), reset(t) method (t optional).
- Serialization: add
s.latched and s.resettimes to toStruct / fromStruct (note existing lowercase field convention, e.g. s.minduration). Old serialized dashboards lack the fields → default false / [].
Value
Directly serves the dashboard-watching engineer: a transient excursion is no longer missed. Latching is the standard operator-acknowledge workflow and pairs naturally with the existing EventStore emission and MinDuration/hysteresis controls.
Constraints check
- Toolbox-free: ✅ pure logical FSM, no toolbox calls.
- Backward-compatible: ✅
Latched defaults false (behavior unchanged); reset() is additive; serialized dashboards without the new fields load with latch off.
- Pure MATLAB/Octave: ✅ no MEX, no language features beyond the existing class.
- Widget/Tag contract: ✅
getXY() still returns a 0/1 vector on the parent grid — every consumer (widgets, SensorDetailPlot, event emission) works unchanged.
Effort estimate
S–M — one class. Stage-4 latch in recompute_(), a cache_ carry-in for appendData(), a reset(t) method with a recorded reset-boundary list, and two serialization fields.
AI-proposed via /feature-scout — needs a human product decision before implementation.
Problem / motivation
MonitorTagproduces a 0/1 alarm signal that drops back to 0 the instant its condition clears (after any hysteresis /MinDurationdebounce). There is no way to make an alarm hold.That means a self-clearing transient — a spike above threshold that returns to normal before anyone looks — is effectively invisible on a dashboard. A
StatusWidget/NumberWidgetbound to the monitor just shows OK, because by the time the engineer glances at the tile the signal is already back to 0. For the target user (a MATLAB sensor engineer watching a dashboard rather than the live sample stream) this is a real blind spot.Latching / manual-reset alarms are a bedrock alarm-management pattern (ISA-18.2): an alarm, once tripped, stays asserted until an operator acknowledges it, regardless of whether the process value has since returned to normal.
Searches for
latch/manual-resetagainst all issues return nothing — this is not yet tracked. It has surfaced as the queued #2/#3 candidate across several/feature-scoutruns (2026-07-05 e/f/g) without being filed.Proposed feature
Add an opt-in latched alarm mode to
MonitorTag, plus a publicreset()to clear the latch.Latched = false(default preserves today's exact behavior).Latched = true, once the (debounced/hysteresed) signal goes to1it stays1for all subsequent samples until a reset boundary.reset(t)clears the latch as of timet(default: latest sample). Reset boundaries are recorded as state sogetXY()stays deterministic and replayable acrossinvalidate()/recompute().Rough sketch
libs/SensorThreshold/MonitorTag.monly.ConditionFn, Stage 2 hysteresis (AlarmOffConditionFn), Stage 3MinDurationdebounce (seerecompute_()~L606 andapplyHysteresis_()~L682). Add a Stage 4 latch after the debounce: hold the running value at1once set, cleared only at recorded reset boundaries.cache_(mirrorslastHystState_/ongoingRunStart_) soappendData()preserves latch state across the append boundary.Latched(logical property, NV-pair at construction),reset(t)method (t optional).s.latchedands.resettimestotoStruct/fromStruct(note existing lowercase field convention, e.g.s.minduration). Old serialized dashboards lack the fields → defaultfalse/[].Value
Directly serves the dashboard-watching engineer: a transient excursion is no longer missed. Latching is the standard operator-acknowledge workflow and pairs naturally with the existing
EventStoreemission andMinDuration/hysteresis controls.Constraints check
Latcheddefaultsfalse(behavior unchanged);reset()is additive; serialized dashboards without the new fields load with latch off.getXY()still returns a 0/1 vector on the parent grid — every consumer (widgets,SensorDetailPlot, event emission) works unchanged.Effort estimate
S–M — one class. Stage-4 latch in
recompute_(), acache_carry-in forappendData(), areset(t)method with a recorded reset-boundary list, and two serialization fields.AI-proposed via
/feature-scout— needs a human product decision before implementation.