Files
measurement/wiki/Reference-Limitations.md
znetsixe 1a16f9c4f1 docs(wiki): full 5-page wiki matching the rotatingMachine reference format
Replaces the prior stub/partial wiki with a Home + Reference-{Architecture,
Contracts,Examples,Limitations} + _Sidebar structure. Topic-contract and
data-model sections wrapped in AUTOGEN markers for the future wiki-gen tool.
Source-vs-spec contradictions surfaced and flagged inline (not silently
fixed). Pending-review notes mark sections that need a full node review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:42:10 +02:00

118 lines
7.9 KiB
Markdown

# Reference &mdash; 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 &mdash; 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 `<asset.type>.measured.<position>`. A measurement configured as `flow-electromagnetic` will not be picked up by a parent that filters on `flow`. The fix is mechanical &mdash; 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 `<type>.measured.<position>` 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 &mdash; `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 &mdash; 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 &mdash; **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 &mdash; 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 &mdash; 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 &ge; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; Contracts](Reference-Contracts) | Topic + config + child registration (alias map at the end) |
| [Reference &mdash; Architecture](Reference-Architecture) | Code map + per-`Channel` pipeline + lifecycle |
| [Reference &mdash; Examples](Reference-Examples) | Shipped flows + debug recipes |
| [rotatingMachine &mdash; Limitations](https://gitea.wbd-rd.nl/RnD/rotatingMachine/wiki/Reference-Limitations) | Where the most common consumer's caveats overlap |