218 lines
11 KiB
Markdown
218 lines
11 KiB
Markdown
|
|
# Reference — Limitations
|
||
|
|
|
||
|
|

|
||
|
|
|
||
|
|
> [!NOTE]
|
||
|
|
> What `generalFunctions` does not do, current rough edges, stability/versioning rules, and open questions. For an intuitive overview, return to [Home](Home).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## When NOT to depend on this library
|
||
|
|
|
||
|
|
- **Passive HTTP gateway nodes** (e.g. `dashboardAPI`) may skip `BaseDomain` and `BaseNodeAdapter` entirely if they hold no domain state. A plain Node-RED node with HTTP endpoints needs only `logger`, `outputUtils`, and `configManager`. See the `dashboardAPI` wiki for the rationale.
|
||
|
|
- **External scripts or standalone tools** that need only unit conversion can import just `const { convert } = require('generalFunctions')` without pulling in the full domain stack.
|
||
|
|
- **Nodes at a different S88 level** that inherit from a third-party base class must not import from `src/domain/` or `src/nodered/` internal paths — they may only use root-level exports.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Known limitations
|
||
|
|
|
||
|
|
### 1. `loadCurve` is deprecated
|
||
|
|
|
||
|
|
`loadCurve(modelId)` is kept as a thin shim over `assetResolver.resolve('curves', modelId)` so legacy consumers don't have to change in one go. New code should use `assetResolver` directly. Replacement `loadModel` exists but not every node has migrated.
|
||
|
|
|
||
|
|
- **Tracked in**: `OPEN_QUESTIONS.md` — Phase 8.5 cleanup.
|
||
|
|
|
||
|
|
### 2. `outlierDetection` (`DynamicClusterDeviation`) prints to `console.log`
|
||
|
|
|
||
|
|
The dynamic-cluster outlier detector emits diagnostic lines via `console.log` directly, bypassing the structured `logger`. This means its output cannot be silenced per-node and doesn't honour `logLevel`. Fix is routing through `logger` like the rest of the library.
|
||
|
|
|
||
|
|
- **Tracked in**: Code review backlog.
|
||
|
|
|
||
|
|
### 3. `configUtils.initConfig` silently strips unknown keys
|
||
|
|
|
||
|
|
When the user config carries a key that isn't in the schema, `configUtils.initConfig` (via `validationUtils.validateSchema`) silently drops it. This means a typo in an editor field name or a missed schema entry results in the default value being used — with no error, no warning, no log line.
|
||
|
|
|
||
|
|
Workaround: the schema must include every key the domain reads, with a sensible default. The 2026-05-11 monster schema fix was a direct consequence of this gotcha.
|
||
|
|
|
||
|
|
- **Tracked in**: `OPEN_QUESTIONS.md` — e.g. monster schema fix.
|
||
|
|
|
||
|
|
### 4. `state` (FSM) and `predict` are not yet integrated with `BaseDomain` lifecycle
|
||
|
|
|
||
|
|
The state machine and the prediction class are exported but not lifecycle-managed by `BaseDomain`. Consumer nodes wire them manually in `configure()` — constructor, event subscriptions, teardown. A second wave of refactor work will move them under the `BaseDomain` umbrella so subclasses get them for free.
|
||
|
|
|
||
|
|
- **Tracked in**: Architecture backlog.
|
||
|
|
|
||
|
|
### 5. `menuUtils` / `MenuManager` bypass the Node.js import path
|
||
|
|
|
||
|
|
These are served as browser JavaScript via the admin `endpointUtils` and run in the Node-RED editor's iframe. Deep changes require testing in both environments (Node-side schema validation, browser-side editor form rendering). There is no automated test harness for the browser side.
|
||
|
|
|
||
|
|
- **Tracked in**: `endpointUtils.js` comments.
|
||
|
|
|
||
|
|
### 6. `CascadePIDController` has no dedicated test suite
|
||
|
|
|
||
|
|
`PIDController` is unit-tested; the cascade variant is not. Adding tests is on the backlog.
|
||
|
|
|
||
|
|
- **Tracked in**: Test backlog.
|
||
|
|
|
||
|
|
### 7. Wiki autogen is hand-maintained
|
||
|
|
|
||
|
|
The API surface section is hand-maintained between the `<!-- BEGIN/END AUTOGEN: api-surface -->` markers in `CONTRACT.md`. There is no `npm run wiki:all` script (yet); when an export is added or changed, the table must be edited by hand. Mitigation: the source-of-truth is the barrel (`index.js`); when in doubt, trust the barrel.
|
||
|
|
|
||
|
|
- **Tracked in**: Phase 9 follow-up.
|
||
|
|
|
||
|
|
### 8. Single-side pressure handling lives in consumers
|
||
|
|
|
||
|
|
Consumer-node concerns like single-side pressure degradation, residue handling, and sequence-abort semantics are NOT centralised in this library — each consumer (`rotatingMachine`, `valveGroupControl`, …) implements its own variant. Cross-node consistency is by convention, not by enforcement. A future `BaseDomain` extension could pull common pressure-routing patterns up.
|
||
|
|
|
||
|
|
- **Tracked in**: Internal architecture notes.
|
||
|
|
|
||
|
|
### 9. Asset registry backends are not fully symmetric
|
||
|
|
|
||
|
|
`FileBackend` is the production default (sync, in-process JSON). `HttpBackend` is provided for remote-resolver scenarios but has fewer call sites and less test coverage. If you switch to `HttpBackend` in production, expect to find edge-case differences.
|
||
|
|
|
||
|
|
- **Tracked in**: Internal — not yet ticketed.
|
||
|
|
|
||
|
|
### 10. No editor form
|
||
|
|
|
||
|
|
`generalFunctions` is never placed in a flow. It has no Node-RED type registration, no `.html`, no admin endpoint of its own. Consumer nodes expose their own editor forms; each form field writes into a config key that `configManager.buildConfig` validates against the node's schema in `src/configs/<nodeName>.json`. This is a deliberate design choice, not a limitation — documented here for visitors searching for "where's the editor form".
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Stability + versioning
|
||
|
|
|
||
|
|
Source of truth: [`.claude/rules/general-functions.md`](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/rules/general-functions.md) in the superproject.
|
||
|
|
|
||
|
|
| Category | Rule |
|
||
|
|
|:---|:---|
|
||
|
|
| **Safe to add** | New named exports. New optional methods on existing classes. New config keys with defaults in the schema. |
|
||
|
|
| **Requires decision-gate interview** | Removing or renaming any export. Changing a method signature. Changing the output key format of `MeasurementContainer.getFlattenedOutput()`. Changing the `formatMsg` delta-compression behaviour. |
|
||
|
|
| **Forbidden without migration** | Breaking the 4-segment key shape (`type.variant.position.childId`). Changing Port 0/1/2 payload envelope. Changing the [CONTRACTS.md](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/refactor/CONTRACTS.md) §1–§9 shapes. |
|
||
|
|
|
||
|
|
### Cross-node impact
|
||
|
|
|
||
|
|
`generalFunctions` is a git submodule shared by all 12 node repos. **Any change here can break any node.** Before modifying any module:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Identify all consumers of the symbol you're touching.
|
||
|
|
grep -r "require('generalFunctions')" nodes/*/
|
||
|
|
|
||
|
|
# Or for a specific export:
|
||
|
|
grep -rn "BaseDomain\|UnitPolicy\|MeasurementContainer" nodes/*/src/
|
||
|
|
```
|
||
|
|
|
||
|
|
After changes, run the test suites of every affected consumer node, not just `generalFunctions/test/`.
|
||
|
|
|
||
|
|
### Canonical units
|
||
|
|
|
||
|
|
`MeasurementContainer` and all internal processing assume canonical units:
|
||
|
|
|
||
|
|
| Quantity | Canonical |
|
||
|
|
|:---|:---|
|
||
|
|
| Pressure | `Pa` |
|
||
|
|
| Flow | `m3/s` |
|
||
|
|
| Power | `W` |
|
||
|
|
| Temperature | `K` |
|
||
|
|
|
||
|
|
Unit conversion happens at system boundaries (input via `CommandRegistry.units` normalisation, output via `UnitPolicy.output` rendering) — never in core logic. Code that assumes anything else is a bug.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Deprecations
|
||
|
|
|
||
|
|
| Symbol | Status | Replacement | Plan |
|
||
|
|
|:---|:---|:---|:---|
|
||
|
|
| `loadCurve(modelId)` | deprecated | `assetResolver.resolve('curves', modelId)` | Remove after every consumer migrates. Tracked in Phase 8.5. |
|
||
|
|
|
||
|
|
When a symbol is marked deprecated:
|
||
|
|
|
||
|
|
1. The row in `CONTRACT.md` flips to `deprecated` and gains a "removed-in" line.
|
||
|
|
2. Consumers in `nodes/*` are updated to the replacement.
|
||
|
|
3. Each touched node's submodule pin is bumped in the superproject.
|
||
|
|
4. After one release on `development` with no consumers, the export and its row are removed.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Open questions (tracked)
|
||
|
|
|
||
|
|
| Question | Where it lives |
|
||
|
|
|:---|:---|
|
||
|
|
| Phase 8.5: complete `loadCurve` → `assetResolver` migration | Internal |
|
||
|
|
| Route `DynamicClusterDeviation` log lines through `logger` | Code review backlog |
|
||
|
|
| Surface a warning when `configUtils.initConfig` strips a key not in schema | `OPEN_QUESTIONS.md` |
|
||
|
|
| Move `state` (FSM) and `predict` under `BaseDomain` lifecycle | Architecture backlog |
|
||
|
|
| Browser-side test harness for `menuUtils` | `endpointUtils.js` |
|
||
|
|
| Test suite for `CascadePIDController` | Test backlog |
|
||
|
|
| Wiki autogen script (`npm run wiki:all`) for the API surface section | Phase 9 follow-up |
|
||
|
|
| `HttpBackend` test coverage parity with `FileBackend` | Internal |
|
||
|
|
| Centralised single-side-pressure handling pattern in `BaseDomain` | Internal architecture notes |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Migration notes
|
||
|
|
|
||
|
|
### Pre-refactor: per-node `registerChild` switch
|
||
|
|
|
||
|
|
The `ChildRouter` replaces hand-written `registerChild(child)` methods. The mechanical migration:
|
||
|
|
|
||
|
|
```js
|
||
|
|
// Before:
|
||
|
|
registerChild(child) {
|
||
|
|
switch (child.softwareType) {
|
||
|
|
case 'measurement':
|
||
|
|
if (child.config.asset.type === 'pressure' && child.positionVsParent === 'upstream') {
|
||
|
|
this._onUpstream(child);
|
||
|
|
} else if (child.config.asset.type === 'flow') {
|
||
|
|
this._onFlow(child);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case 'machinegroup':
|
||
|
|
this._onMgcChild(child);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// After (in configure()):
|
||
|
|
this.router
|
||
|
|
.onMeasurement('measurement', { type: 'pressure', position: 'upstream' }, (data, child) => this._onUpstream(child))
|
||
|
|
.onMeasurement('measurement', { type: 'flow' }, (data, child) => this._onFlow(child))
|
||
|
|
.onRegister('machinegroup', (child) => this._onMgcChild(child));
|
||
|
|
```
|
||
|
|
|
||
|
|
Behaviour is identical (the underlying `childRegistrationUtils` calls are unchanged); the wiring is just declarative.
|
||
|
|
|
||
|
|
### Pre-refactor: per-node `getStatusBadge` duplication
|
||
|
|
|
||
|
|
The `statusBadge` pure-function helpers replaced 12 copies of slightly different status-text formatters. New domains should use `statusBadge.compose(parts, opts)`, `statusBadge.error(msg)`, `statusBadge.idle(label)` instead of building `{fill, shape, text}` by hand. Text is clipped to 60 chars to fit the Node-RED editor.
|
||
|
|
|
||
|
|
### Pre-AssetResolver: `loadCurve` shim
|
||
|
|
|
||
|
|
Old code:
|
||
|
|
|
||
|
|
```js
|
||
|
|
const { loadCurve } = require('generalFunctions');
|
||
|
|
const curve = loadCurve('SomeModel');
|
||
|
|
```
|
||
|
|
|
||
|
|
New code (preferred):
|
||
|
|
|
||
|
|
```js
|
||
|
|
const { assetResolver } = require('generalFunctions');
|
||
|
|
const curve = assetResolver.resolve('curves', 'SomeModel');
|
||
|
|
```
|
||
|
|
|
||
|
|
The shim still works, but the next API-surface review may remove it. Migrate when next touching the file.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Related pages
|
||
|
|
|
||
|
|
| Page | Why |
|
||
|
|
|:---|:---|
|
||
|
|
| [Home](Home) | Intuitive overview |
|
||
|
|
| [Reference — Contracts](Reference-Contracts) | Full public API surface, per-export stability tags |
|
||
|
|
| [Reference — Architecture](Reference-Architecture) | Three-tier rule, `src/` layout, consumer responsibilities |
|
||
|
|
| [Reference — Examples](Reference-Examples) | Usage patterns: extending base classes, registering commands, declaring child routes |
|
||
|
|
| [Platform CONTRACTS.md](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/refactor/CONTRACTS.md) | The authoritative platform base-class + protocol spec |
|
||
|
|
| [`.claude/rules/general-functions.md`](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/rules/general-functions.md) | Stability + change-impact rules |
|