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>
8.4 KiB
Reference — Limitations
Note
Pending full node review (2026-05). What
settlerdoes not do, current rough edges, and open questions. Open items live in.agents/improvements/IMPROVEMENTS_BACKLOG.mdin 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.
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 — 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 — 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
_connectMeasurementfilter 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—F_in = 0,Cs_in = [0...], the three envelopes carry zero flow but valid (zero)Carrays. Should not crash a downstream consumer, but un-tested. - Port 0 with
returnPumpregistered but no flow measurement landed yet —returnPump.measurements.type('flow').variant('measured').position('atEquipment').getCurrentValue()returnsundefined→Math.min(undefined, F_s) = NaN.F_srbecomesNaN→ bothinlet=1andinlet=2carryNaNflow.
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 — it picks the first envelope regardless of inlet number. Open question whether to make the selection inlet-aware.
Stateful telemetry — 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 — not yet ticketed |
| Multi-reactor upstream support — 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 → #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 — pre-fix settler would crash with Cannot read properties of undefined (reading 'payload'). The fix:
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 | Intuitive overview |
| Reference — Contracts | Topic + config + child filters |
| Reference — Architecture | Code map, reactor ↔ settler wiring, mass-balance math |
| Reference — Examples | Shipped flows + the TODO list for production-grade demos |
| reactor — Limitations | The upstream parent — effluent shape contract |
| EVOLV — output-coverage rule | Platform-wide output-coverage requirement |