# Reference — Limitations ![code-ref](https://img.shields.io/badge/code--ref-b884c0f-blue) > [!NOTE] > What `measurement` does not do, current rough edges, and open questions. Open items live in `.agents/improvements/IMPROVEMENTS_BACKLOG.md` in the EVOLV superproject; node-local follow-ups are tracked in the superproject's `MEMORY.md` and `.claude/refactor/OPEN_QUESTIONS.md`. > > Pending full node review (2026-05). --- ## When you would not use this node | Scenario | Use instead | |:---|:---| | Fusing signals from multiple sensors into one virtual measurement | This node is per-channel only. Aggregate at the parent (e.g. `rotatingMachine` already combines upstream + downstream into a differential). | | Producing a control output / actuating something | This is read-only signal conditioning. Use `rotatingMachine`, `valve`, or another equipment-level node. | | Threshold-trip alarms / latched state | There is no comparator / latch output. Build alarm logic on top of the emitted reading at the parent or in a dashboard rule. | | A "passive" measurement that should not register with a parent | Registration is automatic at startup — not currently opt-out. TODO: confirm whether a "no-parent" mode exists; if not, leave the parent input unwired. | --- ## Known limitations ### Asset type must match the parent's filter exactly Parents subscribe to events by exact string match on `.measured.`. A measurement configured as `flow-electromagnetic` will not be picked up by a parent that filters on `flow`. The fix is mechanical — set `asset.type` to the bare type the parent expects. This is documented in the superproject `MEMORY.md` under "Key Integration Gotchas": > Measurement `assetType: "flow"` required (not "flow-electromagnetic") for pumpingStation/monster. ### Position labels lowercase only in the event name The event name emits `.measured.` with `position` lowercased (`upstream`, `downstream`, `atequipment`). The `positionVsParent` field in the `child.register` payload, however, is sent **as configured** (preserves case). If a parent indexes children by the register-payload position string, mixed-case there will not match the lowercase position in subsequent events. Document the convention in any new parent that joins measurement. ### Legacy `source.emitter` `source.emitter` fires `'mAbs'` on the analog `inputValue` setter alongside the canonical `measurements.emitter` path. It is kept for the editor status badge during the refactor window and is **slated for removal in Phase 7**. New consumers must use `measurements.emitter`. ### Digital mode — `notifyOutputChanged()` not explicitly called `Measurement.handleDigitalPayload` collects a per-key summary but does not directly call `notifyOutputChanged()`. The analog `inputValue` setter does. TODO: confirm whether digital-mode Port 0 emissions rely on the next `tick()` or a follow-up notify path inside `BaseNodeAdapter`. Until verified, treat digital-mode Port 0 latency as "up to one tick" (1000 ms). ### Digital mode — per-channel scaling / smoothing fall back to the analog block When a `config.channels[i]` entry omits a per-channel `scaling`, `smoothing`, `outlierDetection`, or `interpolation`, the missing fields fall back to the node-level config — **not** to a sensible per-type default. Setting `smoothing.smoothMethod = 'kalman'` at the node level applies that to every digital channel that does not override it. Operators should set every block per channel in production digital flows. ### `data.measurement` accepts numeric strings — not arrays / NaN The analog handler parses with `Number(p)` and rejects `NaN`. Empty / whitespace strings are skipped silently. Arrays are not accepted in either mode and log a warn in digital mode. ### Simulator does not respect outlier detection `Simulator.step()` writes directly into `m.inputValue`. The downstream `Channel.update` does run outlier detection if enabled — but the simulator's random walk is well-behaved enough that this is effectively a no-op. Don't expect the outlier path to be exercised by the simulator alone. ### `cmd.calibrate` requires ≥ 2 stored values `Calibrator.isStable()` returns `{isStable:false}` when `storedValues.length < 2`. The legacy `Measurement.isStable()` wrapper returns a bare `false` in that case. A fresh calibration call before any data has arrived is silently rejected. ### Calibration baseline depends on `scaling.enabled` When `scaling.enabled` is true, the calibration baseline is `scaling.inputMin`. When disabled, it is `scaling.absMin`. Toggling `scaling.enabled` after calibrating shifts the meaning of the captured offset; recalibrate after any scaling-toggle. ### Smoothing buffer not cleared on config change Changing `smoothing.smoothMethod` or `smoothing.smoothWindow` at runtime does not clear `storedValues`. A previously-mean-smoothed buffer can produce a stale first sample after switching to `lowPass` until the window churns. The conservative workaround is to redeploy. ### `outlierDetection.enabled` mirrored only into `analogChannel` `toggleOutlierDetection()` propagates the new boolean to `this.analogChannel.outlierDetection.enabled` only. In digital mode the per-channel `Channel.outlierDetection.enabled` is **not** updated by the toggle. TODO: digital-mode parity for `set.outlier-detection`. ### Min/max counters never reset `totalMinValue` / `totalMaxValue` / `totalMinSmooth` / `totalMaxSmooth` are monotonic over the node's lifetime. There is no explicit reset command. The smooth-min/max additionally have a "first-write" rule that snaps both to the first value — before that, both read `0`, which can mislead downstream chart axes. --- ## Open questions (tracked) | Question | Where it lives | |:---|:---| | Should digital-mode `notifyOutputChanged()` fire on every accepted update? | Internal — pending P9 review | | Drop the legacy `source.emitter 'mAbs'` event | Phase 7 removal | | Replace legacy `examples/{basic,integration,edge}.flow.json` with Tier-1/2/3 visual-first flows | Superproject `MEMORY.md` "TODO: Example Flows" | | Add `data.clear-min-max` / `data.reset` topic for the rolling counters | Internal | | Add per-channel `set.outlier-detection` for digital mode | Internal | | Auto-recalibration heuristics (currently operator-triggered only) | Internal | | Per-channel `smoothing` window-clear on config change | Internal | --- ## Migration notes ### From pre-refactor flat config Older flows used `assetType` / `supplier` / `category` at the top level of the editor config. `nodeClass.buildDomainConfig` reshapes the editor's flat `uiConfig` into the nested domain config slice (`scaling`, `smoothing`, `simulation`, `calibration`, `mode`, `channels`), so legacy flows continue to deploy. The migration is best-effort — re-saving each measurement node in the editor regenerates the canonical shape. ### From analog-only Adding `config.mode.current` was additive. Flows that omit it default to `analog` and behave exactly as before. To switch to digital: set the editor's "Input Mode" to `digital` and define `config.channels`. ### From legacy alias topics `simulator`, `outlierDetection`, `calibrate`, `measurement` continue to work; each emits a one-time deprecation warning on first fire. Prefer the canonical `set.simulator` / `set.outlier-detection` / `cmd.calibrate` / `data.measurement` for new flows. --- ## Related pages | Page | Why | |:---|:---| | [Home](Home) | Intuitive overview | | [Reference — Contracts](Reference-Contracts) | Topic + config + child registration (alias map at the end) | | [Reference — Architecture](Reference-Architecture) | Code map + per-`Channel` pipeline + lifecycle | | [Reference — Examples](Reference-Examples) | Shipped flows + debug recipes | | [rotatingMachine — Limitations](https://gitea.wbd-rd.nl/RnD/rotatingMachine/wiki/Reference-Limitations) | Where the most common consumer's caveats overlap |