Files
settler/wiki/Reference-Limitations.md

117 lines
8.4 KiB
Markdown
Raw Permalink Normal View History

# Reference — Limitations
![code-ref](https://img.shields.io/badge/code--ref-a3583a3-blue)
> [!NOTE]
> Pending full node review (2026-05). What `settler` does not do, current rough edges, and open questions. Open items live in `.agents/improvements/IMPROVEMENTS_BACKLOG.md` in the superproject.
---
## When you would not use this node
| Scenario | Use instead |
|:---|:---|
| Primary sedimentation upstream of biological treatment | The species 7–12 zeroing in the effluent stream is wrong for primary sludge (the soluble / particulate split is different). Model as a separate node. |
| Generic mass-balance transform | The 13-species ASM3 concentration vector is hard-coded; `Cs[12]` (`X_TS`) is the only species the split is keyed off. Not a fit for arbitrary stream-splitting. |
| Single-tank SBR with no separation stage | The 3-stream output expects a downstream consumer that routes by `payload.inlet`. A direct reactor → reactor wire is lighter. |
| A reactor — you want to model biological transformation, not separation | `reactor` (settler is a passive separator, not a biological process). |
| A return-pump itself — you want to model the pump's behaviour | `rotatingMachine` (settler reads the pump's measured flow but does not control it). |
---
## Known limitations
### Example flows are stub level
The three shipped flows (`basic.flow.json`, `integration.flow.json`, `edge.flow.json`) are 4-node skeletons (tab + node + inject + debug). They prove the node loads in Node-RED but do not exercise the reactor → settler → pump chain, do not drive `data.influent` with a valid payload, and do not have a dashboard tier. Production-grade examples are TODO — see [Reference — Examples — TODO](Reference-Examples#todo--production-grade-example-set).
### Editor colour drift
`settler.html` declares `color: '#e4a363'` (orange). The S88 Unit level requires `#50a8d9` (blue). The placement-rule registry (`.claude/rules/node-red-flow-layout.md` §14) already maps `settler` to the `UN` lane regardless of editor colour, so demos lay out correctly; the cosmetic mismatch is tracked in §16 of the same rule and is on the colour-cleanup list. The wiki diagrams use the correct blue.
### Single-reactor upstream slot
`this.upstreamReactor` is a single slot. Registering a second `reactor` child with `positionVsParent='upstream'` silently overwrites the first — the listener on the previous reactor's `emitter` is not detached, so it keeps firing into a settler that will pull effluent from the new reactor instead. Tracked.
### `X_TS` index is hard-coded
The mass balance uses `Cs_in[12]` (the ASM3 `X_TS` lumped solids species) as the surrogate for total suspended solids. Any change to the species ordering in the upstream reactor breaks settler. The coupling is not documented in the schema — it lives only in the `getEffluent` math and the `_updateMeasurement` switch case for `quantity (tss)`. Tracked.
### No flow-balance warning
When influent solids exceed the target return concentration (`Cs_in[12] > C_TS`), `F_s` is clamped to `F_in` and clarified effluent drops to zero. This is mathematically correct but masks an upstream problem (overloaded reactor, miscalibrated `C_TS` setpoint). The clamp fires silently &mdash; no warn, no badge change beyond the eventual `F_in <= 0` idle state. Operator must monitor `F_eff` directly. Tracked.
### `quantity (tss)` measurement passes through but doesn't validate
`_connectMeasurement` re-emits every measurement type, but `_updateMeasurement` only acts on `quantity (tss)`. Other types log an `error` (`Type '<x>' not recognized for measured update.`) but the re-emit already happened &mdash; the parent of settler still sees the value. Whether this is desired (settler acts as telemetry pass-through) or a contract gap is unresolved.
> [!NOTE]
> Pending full node review (2026-05). Open question: should `_connectMeasurement` filter by asset-type at register time and reject non-`quantity (tss)` children, or continue accepting everything as pass-through telemetry?
### No output manifest / no degraded-state coverage
Per the platform output-coverage rule (`.claude/rules/output-coverage.md`), every node needs a `test/_output-manifest.md` enumerating every Port 0 / 1 / 2 key and a `test/basic/output-*.test.js` exercising each one in both populated **and** degraded states. Settler has neither. The most likely degraded-state crash points:
- Port 0 emitted before any reactor `stateChange` &mdash; `F_in = 0`, `Cs_in = [0...]`, the three envelopes carry zero flow but valid (zero) `C` arrays. Should not crash a downstream consumer, but un-tested.
- Port 0 with `returnPump` registered but no flow measurement landed yet &mdash; `returnPump.measurements.type('flow').variant('measured').position('atEquipment').getCurrentValue()` returns `undefined` &rarr; `Math.min(undefined, F_s) = NaN`. `F_sr` becomes `NaN` &rarr; both `inlet=1` and `inlet=2` carry `NaN` flow.
Tracked. TODO before trial-readiness: add the manifest, tests, and `null`-flow-measurement handling.
### `reactor.getEffluent` shape coupling
`_connectReactor` does `Array.isArray(raw) ? raw[0] : raw` to absorb both the older single-envelope shape and the newer 3-stream array shape of `reactor.getEffluent`. The 2026-03-02 fix is the only thing keeping the older shape alive in production. If `reactor.getEffluent` ever returns a 3-stream array and settler should consume `inlet=0` specifically, the current `raw[0]` selector works by accident &mdash; it picks the first envelope regardless of inlet number. Open question whether to make the selection inlet-aware.
### Stateful telemetry &mdash; no decay / no TTL
The MeasurementContainer holds the last-known value of every re-emitted measurement forever. If a child stops publishing, the stale value persists on Port 1 indefinitely. There is no TTL, no `data.clear-measurement` topic, and no health flag like `rotatingMachine`'s `predictionQuality`. Open question.
---
## Open questions (tracked)
| Question | Where it lives |
|:---|:---|
| Filter `_connectMeasurement` by asset-type at register time? | Internal &mdash; not yet ticketed |
| Multi-reactor upstream support &mdash; teardown ordering, listener detach | Internal |
| Flow-balance warning when `F_s` clamp fires | Internal |
| Inlet-aware selection in `_connectReactor` shape handling | Internal |
| Measurement TTL / staleness flag | Internal |
| Production-grade example flows (Tier 1 / 2 / 3) | `.agents/improvements/IMPROVEMENTS_BACKLOG.md` |
| Output manifest + degraded-state tests | `.claude/rules/output-coverage.md` (platform-wide rule) |
| Editor colour cleanup (`#e4a363` &rarr; `#50a8d9`) | `.claude/rules/node-red-flow-layout.md` §16 |
---
## Migration notes
> [!NOTE]
> Pending full node review (2026-05). No structural migrations have been performed on settler since the AssetResolver refactor of rotatingMachine; the notes below document the one historical fix on record.
### From pre-2026-03-02 `_connectReactor`
Before 2026-03-02 `_connectReactor` assumed `reactor.getEffluent` always returned an array, and indexed `[0]` unconditionally. After the reactor refactor, `getEffluent` returns a single envelope &mdash; pre-fix settler would crash with `Cannot read properties of undefined (reading 'payload')`. The fix:
```js
const raw = this.upstreamReactor.getEffluent;
const effluent = Array.isArray(raw) ? raw[0] : raw;
```
If you maintain a fork of settler from before that date, port this guard.
### From topic-aliased payloads
Both `influent` and `setInfluent` are accepted as aliases for `data.influent`. A one-time deprecation warning fires the first time each alias is seen. Tracked for removal; use the canonical `data.influent` in new flows.
---
## Related pages
| Page | Why |
|:---|:---|
| [Home](Home) | Intuitive overview |
| [Reference &mdash; Contracts](Reference-Contracts) | Topic + config + child filters |
| [Reference &mdash; Architecture](Reference-Architecture) | Code map, reactor &harr; settler wiring, mass-balance math |
| [Reference &mdash; Examples](Reference-Examples) | Shipped flows + the TODO list for production-grade demos |
| [reactor &mdash; Limitations](https://gitea.wbd-rd.nl/RnD/reactor/wiki/Reference-Limitations) | The upstream parent &mdash; effluent shape contract |
| [EVOLV &mdash; output-coverage rule](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/rules/output-coverage.md) | Platform-wide output-coverage requirement |